C++中成员变量的初始化操作(4)---《Effective C++》

时间:2022-07-01 19:49:54

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

C++类中的成员变量,我们一般都是对其进行赋值操作,如:

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 numTimeConsulted;
};
ABEntry::ABEntry(const std::string& name,const std::string& address,const std::list<PhoneNumber>& phones){
theName=name;
theAddress=address;
thePhones=phones;
numTimeConsulted=0;
}

上面的这种操作都是赋值操作,而非初始化操作,初始化发生的时间更早,发生于这些成员的default构造函数被自动调用之时,比进入构造函数本体的时间更早一些,相当于先执行了初始化操作,然后执行了复制操作,效率较低。
我们怎样解决这种问题呢?直接对其执行初始化操作,提高效率,有一种优化的方法称之为成员初始列的替换赋值动作,如

ABEntry::ABEntry(const std::string& name,const std::string& address,const std::list<PhoneNumber>& phones):
theName(names),
theAddress(address),
thePhones(phones),
numTimesConsulted(0)
{}

这中操作成为成员初始列方法,都是初始化操作,构造函数本体不必有任何动作,theName以name为初值进行copy构造,以此类推。

C++中对于成员的初始化顺序要求尤其严格,static变量在类内部申明,在类外部定义,同时如果想要修改static成员变量的值,只能通过在调用类中定义的static成员函数进行修改。

#include <iostream>
#include <cstring>
using namespace std;
class TextBlock{
public:
TextBlock(string s){
this->text = s;
}
const char& operator[](std::size_t position)const{
cout << "我为const代言" << endl;
return text[position];
}
char& operator[](std::size_t position){
cout << "我为non-const代言" << endl;
return text[position];
}
static int i;
static int changeStatic(int &i){
i = 100;
return i;
}
private:
std::string text;

};
int TextBlock::i = 10;
TextBlock::i = 1000;

如果我们这样进行强制修改的话会出错提示,没有存储类或者类型说明符。
对于C++中的non-local static成员变量,解释一下,non-local static成员变量包括global对象,namespace作用域,class内,file作用域中所有被申明为static的对象,而local static成员变量指的是在函数中定义的static成员变量,由于non-local static成员变量的初始化顺序可能存在依赖关系,而这种依赖关系不一定被满足,如下面代码所示:

class FileSystem{
public:
...
std::size_t numDisks() const;
...
}
extern FileSystem tfs;
class Directory{
public:
Directory(params);
...
}
Directory::Directory(params){
...
std::size_t disks=tfs.numDisks();//使用tfs对象
...
}
Directory tempDir(params);

可以看出tfs必须在tempDir之前仙贝初始化,否则tempDir的构造函数会用到尚未被初始化的tfs。
因此我们需要一种方法进行解决这种问题,方法是:将每个non-local static对象搬到自己的专属函数内,该对象在此函数中被申明为static,这些函数返回一个reference指向它所含的对象,修改办法如下:

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

这样可以保证在tfs在tempDir之前被初始化。