您的位置:首页 > 编程语言 > C语言/C++

effect C++ 确定对象被使用前先被初始化

2017-03-22 16:24 302 查看

将对象初始化

int x 在某些语境下x保证初始化(为0),但在其他语境中却不保证。

class Point{
int x , int y;
}
....
Point p ;


p的成员变量有时候初始化(为0),有时不会。读取未初始化的值会导致不明确行为。

最佳的处理办法就是:永远在使用对象之前将他们初始化。对于无任何成员的内置类型,必须手工完成此事。

int x =0;
const char * text ="A-C-style string";
double d ;
std::cin>>d;      //以读取input stream的方式完成初始化


确保每一个构造函数都将对象的每一个成员初始化。

注意别混淆了赋值和初始化。

class PhoneNumber {...}
class ABEntry{
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=name;         //这些都是赋值
theAddress=address;   //而非初始化
thePhones=phones;
numTimesConsulted=0;
}


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

较佳的一个写法是:

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


通常效率更高,基于赋值的那个版本首先调用default构造函数为成员赋初值,然后立刻重新赋值。

总使用成员初值列。

不同编译单元内定义之non-local static 对象

static对象 ,其寿命从构造出来直到程序结束为止(stack和heap-based对象都被排除)。这种对象包括global对象,定义于namesapce作用域的对象、在classes内、函数内、以及在file作用域内被声明为static的对象。 函数内的static对象被称为local static对象(因为它们对函数而言是local),其他的对象称为non-local对象。程序结束时static对象会被自动销毁,它们的析构函数会在main()结束时调用。

编译单元是产出单一目标文件的那些源码,基本是单一源码加上其所含入的头文件。

现在至少有两个源码文件,每一个内含至少一个non-local static 对象(也就是该对象是global或位于namespace作用域内,抑或在class内或file作用域内被声明为static)。真正的问题是:如果某编译单元内某个non-local static对象的初始化动作使用了另一编译单元内的某个non-local static对象,它所用到的这个对象可能未被初始化。

例:

class FileSystem{
public:
...
std::size_t numDisks()const; //众多成员函数之一
...
}
extern FileSystem tfs; //预备给客户使用的对象
假设用户建立一个class

class Directory{
public:
Directory(params);
...
};
Directory::Directory(params)
{
...
std::size_t disks=tfs.numDisks(); //使用tfs对象
...
}
如果客户决定创建一个Director对象

Director tempDir (params);
除非tfs在tempDir之前被初始化,否则tempDir的构造函数会用到尚未初始化的tfs。它们是定义在不同编译单元内的non-local static 对象。

解决:

将每个non-local static 对象搬到自己的专属函数内(该对象在此函数内被声明为static)。这些函数返回一个reference 指向它所含的对象。然后用户调用着这些函数,而不是指涉这些对象。 non-local static 对象被 local static 对象替换了。(Singleton模式的一个常见的实现手法)

C++保证,函数内的local static 对象会在“该函数被调用期间”“首次遇上该对象之定义式”时被初始化。所以如果以“函数调用”(返回一个reference指向local static对象)替换“直接访问non-local static对象”,就可以保证获得的那个reference将指向一个历经初始化的对象。如果从未调用 non-local static 对象的“仿真函数”,就绝不会引发构造和析构成本。

class FileSystem{...}    //同前
FileSystem& tfs()        //这个函数用来替换tfs对象;它在FileSystem class 中可能是个static
{
static FileSystem fs;  //定义并初始化一个local static对象
return fs;             //返回一个reference指向上述对象
}
class Directory{...};      //同前
Directory::Directory(params)
{
...
std::size_t disks =tfs().numDisks();//原本的reference to tfs现在改为tfs()
}
Directory&tempDir()    //这个函数用来替换tempDir对象,它在Directory中可能是一个static
{
static Directory td;   //定义并初始化local static 对象
return td;            //返回一个reference指向上述对象
}


这样,客户使用tfs()和tempDir()而不再是tfs和tempDir,使用的是指向static对象的reference

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

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

为免除“跨编译单元之初始化次序”问题,请以local static 对象替换non-local static 对象。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: