《Effective C++》条款4:确定对象被使用前已被初始化

本条款主要讲解了类成员初始化的问题;

本章的宗旨旨在初始化类成员,保证类成员能够成功初始化,防止未初始化造成使用之外的错误;

 

初始化列表:

作者希望人们使用初始化列表而构造函数体内赋值的方式进行初始化的定义;

class test {
private:
	int a;
	string s;
	double b;
public:
	test(const int& a,const string& s,const double& b):a(a),b(b),s(s){}
};

如上所示,使用初始化列表定义可以有效避免开销;

如果采用构造函数体内进行赋值,则会出现先default构造,再赋值的问题;

而如果直接使用初始化列表方式来进行构建,则只用赋值一次,直接default构造;

 

同时,值得注意的是初始化的顺序,有两大原则:

1.基类优先于派生类进行初始化;

2.对于类内成员,优化顺序和初始化值表的顺序相同

所以需要谨慎的是初始化值表顺序的构造,顺序不同可能会影响初始化的预期;

class test {
private:
	int a;
	string s;
	double b;
	string ss;
public:
	test(const int& a,const string& s,const double& b):a(a),b(b),s(s),ss(s+'2'){}
};

正如该例子所示,ss和s的初值随着初始化值列表的不同而可能出现二义性;

 

关于static对象的初始化问题:

这里需要注意一下static对象和static关键字的区别;

首先注意一下static对象的定义:指global对象、用于namespace作用域内的对象,以及classes内、函数内、以及再file作用域内声明为static的对象;

 

首先static对象可以分为两大部分:

1.local-static对象:函数内的使用static声明的对象;

2.non-local-static对象:除了在函数内使用static声明的其他static对象;

 

对于static对象,存在问题的是调用链问题,也就是对于多个文件内的初始化顺序问题;

例如:A,B两个类,A是B的类内元素,所以一般需要先初始化B中的A,再初始化B,但是并不能确保这样的顺序;

 

问题根源:C++只保证了单类中的构造顺序,对于多个类的调用链不能保证初始化的先后;

 

解决方案:使用local-static对象来进行解决:

使用函数返回static对象,来进行local-static对象构造;

class FileSystem{
private:
	int value;
public:
	FileSystem() :value(0) {};
	int rv() {
		return value;
	}
};

class Directory {
public:
	Directory() {
		int x = tfs().rv();
	}
};

FileSystem& tfs() {
	static FileSystem fs;
	return fs;
}

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

通过函数返回local-static对象,可以再返回的时候完成对象的构造,从而不用关心是多个类初始化构造的问题;

该种技术称之为reference-returning,后续也会有更多的章节详细介绍多线程下的static对象技术,因为多线程中极易引起混乱

 

存在问题:

1.static关键字复习;

2.关于local-static生命周期的问题;

3.引用和指针的详细归类;

4.extern声明的问题;

 

posted @ 2020-12-02 21:14  暮云林凌  阅读(92)  评论(0)    收藏  举报