条款4——确定对象被使用前已先被初始化
终于连上网了。过了几天没有网的日子还可以....现在手头有本More Effective C++打算边翻翻看这本书,边写日志复习 Effective C++
这条规矩我想人人都知道,可是却时常被忘记。而我们的伙伴C++也常常淘气搞怪。比如说
int x,这个有时候x被初始化了,有时候没有。在类中比如
class Point{
int x,y;
...
};
point P;
这个x,y就有时候会初始化为0,有时候又不会。要想分辨并记住这些不同情况比较麻烦,好,我们莫不如手工完成这件事——针对所有的内置类型
int x=0;
const char* text="hello world";
double d;
std::cin>>d;//以读取输入流的方式初始化。
赋值与初始化
那么针对其他自定义类型呢???这就是我们大名鼎鼎构造函数的任务了。首先呢大家先考虑一下什么是赋值(assignment)什么是初始化(initialization)。这个真的很容易混淆。
class PhoneNumber{...}
class EXAMPLE{
public:
EXAMPLE(const string& name,const string& address,const list<PhoneNumber>& phones)
private:
string theName;string theAddress;list <PhoneNumber> thePhones;int x;};
我们看到了上面的构造函数,如果我们这样
EXAMPLE::EXAMPLE(.....)
{
theName=name;//这是赋值,不是初始化
theAddress=address;//赋值
thePhones=phones;//赋值
x=0//当然这也是赋值
}
C++规定对象成员的变量初始化要在进入构造函数实现部分之前,也就是{...}之前(x除外,它是内置类型)C++给我们提供了以下的形式
EXAMPLE(const string& name,const string& address,const list<PhoneNumber>& phones)
:theName(name),
theAddress(address)//这些都是初始化
ThePhones(phones)
x(0)
{ }
其实这个两种构造函数效果相同,可是使用成员初值列的,也就是第二种,效率更高。为什么呢???下面就将隐藏在背后的东西告诉大家:
第一种:首先调用了string的默认构造函数对theName进行初始化,然后又用name这个变量对它赋值-------因为string也是个类
第二种:直接利用成员初值列,调用了string类中的copy构造函数,对theName进行初始化。------要理解copy构造函数和普通构造函数的话,推
C++中成员初始化次序是固定的。有继承的情况下类与类之间:先基类后子类
类内部:按照变量声明的次序,与初始化列表无关。
不同编译单元内的non-local static对象初始化次序问题
所谓编译单元是指产出单一目标文件的源码。也就是一个源码文件+其头文件
所谓local static对象就是定义在函数内部的static,其他的对象就称为non-local static对象
现在的情况是一个编译单元的某个non-local static对象A初始化动作里使用了另一个编译单元内的某个non-local static对象B,我们无法保证B一定会在A之前已被初始化,C++不给我们这种保证。例如
在编译单元A内我们定义了一个文件系统类
class FileSystem{
public:
...
std::size_t numDisks() const;
...
};
extern FileSystem tfs;
在另一编译单元B内,客户建立另一个类
class Directory{
public:
Directory(params);
...
};
Directtory::Directory(params)
{
...
//用到了tfs对象
std::size_t disks=tfs.numDisks();
}
此时当我们创建一个Directory对象时
Directory tempDir(params);c++不保证tfs一定在tempDir之前初始化。这可以借鉴设计模式中的Singleton。
//编译单元A内
class FileSystem{...};
FileSystem& tfs()
{
static FileSystem fs;
return fs;
}
//编译单元B内
class Directory{...};
Directtory::Directory(params)
{
...
std::size_t disks=tfs().numDisks();//注意这里的形式,与之前不同
}
Director& tempDir()
{
static Directory td;
return td;
}
因为C++保证,函数内的local static对象会在该函数被调用期间首次遇上该对象定义式时被初始化。
好了问题解决了。