Effective C++ T04:确定对象被使用前已先被初始化

38 篇文章 0 订阅
31 篇文章 2 订阅

Effective C++学习笔记总链接

改善程序与设计的55个具体做法学习笔记-每日1条


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

【技巧】:

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

2. 构造函数最好使用成员初始化列表,而不要在构造函数本体内使用赋值操作。

3. 初始化列表的成员变量,其排列次序应该和他们在class中声明次序相同。

4. 为免除“跨编译单元之初始化次序”问题,请以local static对象替换non-local static 对象


读取未初始化的值会导致不明确的行为

永远在使用对象之前先将它初始化,对于无任何成员的内置类型,必须手工完成此事。

至于内置类型之外的任何其他东西,确保每一个构造函数都将对象的每一个成员初始化

构造函数最佳写法,使用初始化列表

// 构造函数的初始化列表
ABEntry::ABEntry(const std::string& name, const std::string& address,
	const std::list<PhoneNumber>& phones)
	:theName(name),theAddress(address),thePhones(phones), numTimesConsulted(0)
	{}		

构造函数的初始化列表和构造函数内赋值,效率更高
对于大多数类型而言,比起先调用default构造函数然后再调用 copy assignment 操作符(构造函数内赋值单只调用一次copy构造函数(初始化列表) 是比较高效的,有时甚至高效得多。
对于内置数据类型,其初始化和赋值成本相同,但为了一致性最好也通过成员初始化列表初始化

总在初始化列表中列出所有成员变量

有些情况下,必须使用初始化列表,不能使用赋值。例如 成员变量为const或references.

总是使用初始化列表,有时候绝对必要,且又往往比赋值更高效

对于许多class拥有多个构造函数

多份成员初始化列表的存在就会导致重复和无聊的工作。

可以合理地在初始化列表中遗漏那些“赋值表现像初始化一样好”的成员变量,改用他们的赋值操作,并将那些赋值操作移往某个函数(通常为private),供所有的构造函数调用。

class 的成员变量总是以其声明次序被初始化

即使它们在成员初始化列表中以不同的次序出现,也不会影响以声明次序初始化成员变量

当你在成员初始化列表中条列各个成员时,最好总是以其声明次序为次序

local static 代替 non-local static,避免不同编译单元初始化次序问题

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

class FileSystem // 来自你的程序库
{
public:
	...
	std::size_t numDisk() const;
	...
};
extern FileSystem tfs; //预备给客户使用的对象

class Directory // 由程序库客户建立
{
publicDirectory(params); 
	...
};
Directory::Directory(params)
{	
	std::size_t disk = tfs.numDisk(); // 使用tfs对象
	...
}

Directory tempDir(params); // 为临时文件而做出的目录

上述程序问题: 除非tfs在tempDir之前先被初始化,否则tempDir的构造函数会用到尚未初始化的tfs。

C++ 对定义于不同的编译单元内的non-local-static对象的初始化相对次序无明确定义。不可能决定正确的初始化次序。无法保证non-local-static对象被其他编译单元调用前被初始化

解决办法:将每个non-local static 搬到自己专属函数内(该对象在此函数内被声明为static),这些函数返回一个reference指向所含的对象。调用这些函数,而不直接指涉这些对象。
class FileSystem { ... }; // 同前
FileSystem& tfs() //该函数替换tfs对象,reference-returning函数
{
	static FileSystem fs;
	return fs;
}

class Directory { ... }; // 同前
Directory::Directory(params)
{	
	std::size_t disk = tfs().numDisk(); // 调用tfs()
	...
}

Directory& tempDir(params) //该函数替换tempDir对象,reference-returning函数
{	
	static Directory td;
	return td;
}

C++保证,函数内的local static对象会在“该函数被调用期间” “首次遇上该对象之定义式”时被初始化。

所以以“函数调用”(返回一个reference指向local static对象)替换“直接访问non-local static对象

从另一个角度讲,函数内含“static 对象”使他们在多线程系统中带有不确定性
解决办法:在程序的单线程启动阶段手工调用所有的reference-returning函数,可消除与初始化有关的“竞速形势”。

总结:为了避免对象初始化之前使用它们,需要做到三点:

1. 手工初始化内置型non-member对象
2. 使用成员初始化列表对付对象的所有成员变量
3. 在“初始化次序不确定性”(针对不同编译单元所定义的non-local static),使用reference-returning 函数
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值