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

  读取未初始化的值会导致不明确的行为。

  在C++中,规则很简单:确保每一个构造函数都将对象的每一个成员初始化。

class PhoneNumber{...};
class ABEntry{                    //ABEntry = "Address Book Entry"
public:
    ABEntry(const std::string& name, const std::strings& address,
const std::list<PhoneNumber>& phones);

private:
    std::strings theName;
    std::string theAddress;
    std::list<PhoneNumber> thePhones;
    int numTimesConsulted;
};

ABEntry::ABEntry(const std::string& name, const std::strings& address,
const std::list<PhoneNumber>& phones)
{
    theName = name;                    //这些都是赋值,不是初始化
    theAddress = address;   
    thePhone = phones;
    numTimesConsulted = 0;
}

这种操作会导致ABEntry对象带有你指定的值,但不是最佳做法。在ABEntry构造函数内,theName,theAddress,thePhones都不是被初始化,而是被赋值。ABEntry构造函数的一个较佳写法是,使用成员列初始列替换赋值动作。

ABEntry::ABEtry(const std::string& name, const std::string& address, 
            const std::list<PhoneNUmbers>& phones)
:theName(name),                                //这些都是初始化
 theAddress(address),
 thePhone(phones),
 numTimesConsulted(0)
{}  

 甚至当你default构造一个成员变量,你都可以使用成员初值列,只要指定无物作为初始化实参即可。

ABEntry::ABEtry()
:theName(),
 theAddress(),
 thePhone(),
 numTimesConsulted(0)                    //初始化numTimesConsulted
{}

 记住一个规则:规定总是在初始值列中列出所有成员变量,以免还得记住哪些成员变量(如果它们在初值列中被遗漏的话)可以无需赋值。

 

  许多class拥有多个构造函数,每个构造函数都有自己的成员初始列。这种情况可以合理的遗漏哪些”赋值和初始化变现一样好”的成员变量,改用它们的赋值操作,并将哪些赋值操作移往某个函数(通常是private),共所有构造函数调用。

 

C++有着固定的成员初始化次序。基类比派生类先初始化,class的成员变量总是以其声明的顺序被初始化。

 

所谓static对象,其寿命从构造出来知道程序结束为止。函数内的static对象称为local static对象(因为它们对于函数而言是local),其他static称为non-static对象。程序结束时static对象会自动销毁,也就是它们的析构函数会在main()结束时被自动调用。

 

 当两个源文件都至少含有一个non-static的对象。如果某编译单元内的non-local static对象的初始化使用了么另一个non-local static对象,它所用的这个对象可能尚未被初始化,因为C++对"定义于不同编译单元内的non-static 对象"的初始化次序并无明确定义。

例:

class FileSystem                //来自你的程序库
{
public:
 ...
 std::size_t numDisks() const;  //众多成员函数之一
 ...
};
extern FileSystem tfs;           //预备给客户使用的对象
class Director            //客户的程序库
{
public:
    Diretory(params);
    ...

};

Director::Directory(params)
{
    ...
    std::size_t disks = tfs.numDisks(); //使用tfs对象
    ...
}
Directory tempDir(params);  //为临时文件而做出的目录

 除非tfs在tempDir之前被初始化。

解决办法:这个办法的基础在于:C++保证函数local static对象在“该函数调用期间”“首次遇上该对象的定义”时被初始化。

class FileSystem{...}
FileSystem& tfs()
{
    static FileSystem fs;     
    return fs;
}
class Directory{...};
Directory::Directory(params)
{
    ...
    std::size_t disks = tfs().numDisks();
    ...
}

Directory& tempDis()
{
    static Directory td;
    return td;
}

 

 

结论:为内置类型对象进行手工初始化,因为C++不保证初始化它们。

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值