读取未初始化的值会导致不明确的行为。在某些平台上,仅仅只是读取未初始化的值,就可能让你的程序终止运行。更可能的情况是读入一些"半随机"bits ,污染了正在进行读取动作的那个对象,最终导致不可测知的程序行为,以及许多令人不愉快的调试过程。

        永远在使用对前先将它初始化。

一、对于无任何成员的内置类型,你必须手工完成此事。例如:

int x = 0;                                                    //对int 进行手工初始化
 const char* text = "A C-style string";     //对指针进行手工初始化
 double d;
 std::cin>> d;                                             // 以读取input s出am 的方式完成初始化

二、至于内置类型以外的任何其他东西,初始化责任落在构造函数( constructors)身上。规则很简单:确保每一个构造函数都将对象的每一个成员初始化。这个规则很容易奉行,重要的是别混淆了赋值(assignment) 和初始化( initialization)。

        考虑一个用来表现通讯簿的class ,其构造函数如下:

class PhoneNumber { ... };
 class ABEntry {                                                                    //ABEntry ="Address Book Entry"
 public:
     ABEntry(const std::string& name, const std::string& address ,const std::list<PhoneNumber>& phones);
 private:
 std::string theName;
 std::string theAddress;
 std::list<PhoneNumber> thePhones;
 int numTimesConsulted;
 ABEntry: :ABEntry(const std: :string& name , const std: : string& address,const std::list<PhoneNumber>& phones)
 theName=narne;                                           //这些都是赋值(assignments) ,
 theAddress = address;                                //而非初始化(initializations)。
 thePhones = phones;
 numTimesConsulted = 0;}
这会导致ABEntry 对象带有你期望(你指定)的值,但不是最佳做法。C++ 规定,对象的成员变量的初始化动作发生在进入构造函数本体之前。

ABEntry 构造函数的一个较佳写法是,使用所谓的member initialization list (成员初值列〉替换赋值动作:
 ABEntry: :ABEntry(const std: :string& n缸ne , const std: :string& address,
 const std::1工st<PhoneNumber>& phones)
 :theNarne(narne) ,
 theAddress(address) ,                            //现在,这些都是初始化(initializations )
 thePhones(phones) ,
 numTimesConsu1ted(0){ }                                                         //I现在,构造函数本体不必有任何动作


这个构造函数和上一个的最终结果相同,但通常效率较高。

 如果成员变量是const 或references,它们就一定需要初值,不能被赋值。避免需要记住成员变量何时必须在成员初值列中初始化,何时不需要,最简单的做法就是:总是使用成员初值列。这样做有时候绝对必要,且又往往比赋值更高效。

而class 的成员变量总是以其声明次序被初始化。回头看看ABEntry. 其theName 成员永远最先被初始化,然后是theAddress. 再来是thePhones. 最后是numTimesConsulted 。即使它们在成员初值列中以不同的次序出现(很不幸那是合法的) ,也不会有任何影响。


三、不同编译单元内定义之non-local static对象"的初始化次序。

函数内的static 对象称为local static 对象(因为它们对函数而言是local) ,其他static对象称为non-local static 对象。程序结束时static 对象会被自动销毁,也就是它们析构函数会在main ()结束时被自动调用。

     所谓编译单元<translation unit)是指产出单一目标文件(single object file) 的那些源码。基本上它是单一源码文件加上其所含入的头文(#includefiles) .

     现在,我们关心的问题涉及至少两个源码文件,每一个内含至少一个non-local static 对象(也就是说该对象是global 或位于namespace 作用域内,抑或在class 内或file 作用域内被声明为static)。真正的问题是:如果某编译单元内的某个non-local static 对象的初始化动作使用了另一编译单元内的某个non-local static 对象,它所用到的这个对象可能尚未被初始化,因为C++ 对"定义于不同编译单元内的non-local static 对象"的初始化次序并无明确定义。

例子:

        假设你有一个FileSystem class ,它让互联网上的文件看起来好像位于本机(local)。由于这个class 使世界看起来像个单一文件系统,你
可能会产出一个特殊对象,位于global 或namespace 作用域内,象征单一文件系统:

class FileSystem {                               //来自你的程序库
 public:
 std::size t numDisks() canst;                    //众多成员函数之一};
 extern FileSystem tfs;                         //预备给客户使用的对象; //tfs 代表"the file system"现在假设某些客户建立了一个class 用以处理文件系统内的目录(directories) 。恨自然他们的class 会用上theFileSystem 对象:
class Directory {                      //由程序库客户建立
 public:
 Directory ( params );
 } ;
 Directory::Directory( params )
 std::size t disks = tfs.numDisks();               //使用tfs 对象
  进一步假设,这些客户决定创建一个Directory对象,用来放置临时文件:Directory tempDir ( params );             //为临时文件而做出的目录
现在,初始化改序的重要性显现出来了:除非tfs 在tempDir 之前先被初始化,否则tempDir 的构造函数会用到尚未初始化的tfs 。但tfs 和ternpDir 是不同的人在不同的时间于不同的源码文件建立起来的,它们是定义于不同编译单元内的non-local static 对象。而你无法确定其初始化顺序。
    一个小小的设计便可完全消除这个问题, 唯一需要做的是:将每个non-local static 对象搬到自己的专属函数内(该对象在此函数内被声明为static) 。这个手法的基础在于: C++ 保证,函数内的local static 对象会在"该函数被调用期间" "首次遇上该对象之定义式"时被初始化。
以此技术施行于tfs 和tempDir 身上,结果如下:
class FileSystem { ... );             // 同前
 FieSystem& tfs (){
 static FileSystem fs;                //这个函数用来替换tfs 对象:它在FileSystemclass 中可能是个static 。return fs;                               //定义并初始化一个local static 对象,返回一个reference 指向上述对象}
class Directory { ... );               // 同前
Directory::Directory( params)
{// 同前,但原本的reference to tfs 现在改为tfs ()
 std::size t disks = tfs() .numDisks( );   
 Directory& tempDir()                   //这个函数用来替换tempDir对象,它在Directoryclass 中可能是个static
 static Directory td;                       //定义并初始化local static 对象,
 return td;                                      //返回→个reference指向上述对象。}


这么修改之后,这个系统程序的客户完全像以前一样地用它,唯一不同的是他们现在使用tfs ()和tempDir()而不再是tfs 和tempDir。也就是说他们使用函数返回的"指向static 对象"的reference,而不再使用static 对象自身。

请记住:

1、为内置型对象进行手工初始化,因为C++不保证初始化它们。
2、构造函数最好使用成员初值列(member initialization list) ,而不要在构造函数本体内使用赋值操作(assignment) 。初值列列出的成员变         量,其排列次序应该和它们在class 中的声明次序相同。
3、为免除"跨编译单元之初始化次序"问题,请以local static 对象替换non-local static 对象。