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

对于内置类型,必须手工完成这件事。
对于其他类型,则依赖于这个类型的构造函数。

首先,最好使用初始化列表而不是在函数体内部进行赋值。原因有两个

1.有些对象只能初始化,不能赋值:举一个简单的例子:const变量。

2.在构造函数体中赋值前,其实已经进行了初始化操作。对于内置类型,这里初始化的都是一些垃圾数字,然后才是赋值。对于自定义类型,先是调用了这个类型的默认构造函数,进行初始化,然后在利用重载的的赋值操作符进行赋值。如果你使用初始化列表,就不用赋值了,节省了一比开销。但要注意的是,初始化列表中初始化的顺序与类的定义中顺序相同,而与列表中的顺序无关。
有一种情况下我们也可以考虑在构造函数体内部完成赋值。因为我们知道发现,对于内置类型,使用初始化列表和赋值的开销是一样的。假如我们有多个构造函数,每个函数都要初始化某几个内置的数据类型,那么我们可以选择把这几个数据类型的赋值初始化写成一个private函数,然后在这些构造函数中调用这个函数。


最后讨论的是一个特殊的问题:不同编译单元内定义的non-local static对象的初始化顺序。
首先,什么是编译单元?简单的说,就是源文件+它包含的头文件,他俩和在一起被编译成一个.o或者.obj。
那什么是non-local static对象?首先,static对象是那些寿命从被构造出来到程序结束为止的对象。它包括:全局对象,定义在namespace作用域的对象,类内、以及在文件作用域中被声明为static的对象。其中函数内部的对象成为local static对象,其他的成为non-local static。
有了这些概念,我们就可以说明这个问题了,先看一个简单的示例程序:

我在头文件中定义了两个类,并声明了两个全局对象:

class Test1
{
public:
	Test1();
	~Test1(){cout<<"Test1析构函数"<<endl;}
};

class Test2
{
public:
	Test2(){cout<<"Test2 构造函数"<<endl;}
	~Test2(){cout<<"Test2析构函数"<<endl;}
	void test2(){cout<<"Test2测试函数"<<endl;}
};

extern Test2 t2;
extern Test1 t1;

值得注意的是Test1的构造函数中调用了t2的test2函数。它们的定义在对应的源文件中:

//t1.cpp
#include "item2.h"

Test1::Test1()
{
		cout<<"Test1 构造函数"<<endl;
		t2.test2();
}

//全局变量
Test1 t1;

//t2.cpp
#include "item2.h"
Test2 t2;

主程序其实没啥:

int main()
{
	cout<<"hello"<<endl;
	return 0;
}

运行结果为:
Test1 构造函数
Test2测试函数
Test2 构造函数
hello
Test2析构函数
Test1析构函数
请按任意键继续. . .
我们发现,对于两个全局变量t1和t2。t1竟然可以在t2还没有初始化的时候调用t2的函数!这里的函数只不过是打印,所以无所谓,但如果是处理数据之类的,可就出问题了!这是因为这两个不同编译单元的non-local static对象初始化的顺序是不定的。
那么问题如何解决呢?其实很简单,就是将每个non-local static对象搬到自己的专属函数里,这些函数返回一个指向它所含对象的引用。

//t2.cpp
#include "item2.h"
Test2& GetT2()
{
	static Test2 t2;
	return t2;
}
//t1.cpp
Test1& GetT1()
{
	static Test1 t1;
	return t1;
}
Test1::Test1()
{
		cout<<"Test1 构造函数"<<endl;
		GetT2().test2();
}

Test1 newTest1;

这次还是那个主函数,注意到这次只有一个全局变量newTest1
Test1 构造函数
Test2 构造函数
Test2测试函数
hello
Test1析构函数
Test2析构函数
请按任意键继续. . .
但是,在调用全局变量newTest1的构造函数时,就会调用Test2的构造函数,避免了Test2的对象还未初始化就能调用它的成员函数的情况。这是因为函数内的local static对象会在该函数被调用期间,首次遇上该对象的定义式时被初始化。


总结起来就是3句话:
1.内置变量手工初始化。
2.类的数据最好通过初始化列表初始化,而不是在构造函数体内赋值。
3.为了解决不同编译单元的non-local static对象初始化顺序问题,最好以local static对象替换non-local static对象。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值