条款04:确定对象被使用前已先被初始化

来源:互联网 发布:平成骑士最终形态数据 编辑:程序博客网 时间:2024/05/23 00:07

 读取未初始化的值会导致不明确的行为。在某些平台上,仅仅只是读取未初始化的值,就可能让你的程序终止运行。更可能的情况的读入一些“半随机”bits,污染了正在读取动作的那个对象,最终导致不可测知的程序行为。

 

如果使用c part of c++而且初始化可能招致运行期成本,那么就不保证发生初始化。一旦进入non-C part of c++,规则有些变化。这就解释了为什么array(来自c part of c++)不保证其内容被初始化,而vector(来自STL part of c++)却有此保证。

 

最佳处理办法:永远在使用对象之前将它初始化。

 

不要混淆了赋值(assignment)和初始化(initialization)。

class Sample{

public:

    Sample(const std::string& name);

private:

    std::string theName;

    int num;

}

Sample::Sample(const std::string& name)

{

    theName = name;    //这些都是赋值

    num = 0;

}

C++规定,对象的成员变量的初始化发生在进入构造函数本体之前。

在Sample构造函数内,theName不是初始化,是赋值。初始化的发生时间更早,发生在这些成员的default构造函数被自动调用之前。但这对num不为真,因为它属于内置类型(就是c/c++中最基本的类型,如int, char,float等都是),不保证在赋值动作的时间点之前获得初值。

Sample构造函数较佳写法是使用所谓的member initialization list(成员初值列)替换赋值动作。

Sample::Sample(const std::string& name)

:theName(name),

num(0)

{}

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

 

有些情况下即使面对的成员变量属于内置类型(那么其初始化与赋值的成本相同),也一定得使用初值列。是的,如果成员变量时const或references,它们就一定需要初值,不能被赋值。为避免需要记住成员变量何时必须在成员初值列中初始化,何时不需要,最简单的做法就是:总是使用成员初值列。这往往比赋值更高效。

许多classes有多个构造函数,每个构造函数有自己的初值列。如果这种class有许多成员变量和/或base classes,多份初值列导致重复和无聊的工作。这时可以再初值列中遗漏“赋值和初始化一样好”的成员变量,改用它们的赋值操作,并把这些赋值操作移往某个函数(通常是private),供所有构造函数调用,这种做法在“成员变量的初值系由文件或数据库读入”时特别有用。然而,比起经由赋值操作完成的“伪初始化”,通过成员初值列完成的“真正初始化”通常更加可取。

C++有着十分固定的“成员初始化次序”。是的,次序总是相同的:base classes更早与其derived classes被初始化。而class的成员变量总是以其声明次序被初始化。为避免你或你的检阅者迷惑,并避免某些可能存在的晦涩错误,在成员初值列中条列各个成员时,最好总是以其声明次序为次序。

 

1.为内置型对象进行手工初始化,因为c++不保证初始化它们。

2.构造函数最好使用成员初值列,而不要在构造函数本体内使用赋值操作。初值列列出来的成员变量,其排列次序应该和他们在class中声明次序相同。

3.为避免“跨编译单元之初始化次序”问题,请以local static对象替换non-local static对象。