Effective C++ 条款04:确定对象被使用前已经先被初始化
规则一 永远在使用对象之前将它初始化
int x = 0;
const char* text = "A C-style string";
double d;
std:: cin >> d;
// 对于内置类型的初始化必须手工完成,其他类型的初始化职责落在构造函数身上。
规则二 确保每一个构造函数都将对象的每一个成员初始化
这个规则很简单,重要的是不要混淆赋值和初始化操作。
class PhoneNumber { ... };
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 numTimesConsulted;
}
ABEntry(const std::string& name, const std::string& address, const std::list<PhoneNumber>& phones) {
theName = name;
theAddress = address; // 这些都是赋值
thePhones = phones; // 而非初始化
numTimesConsulted = 0;
}
C++规定,对象的成员变量的初始化动作发生在进入构造函数本体之前。
初始化发生时间更早,发生于这些成员的default构造函数被自动调用之时(比进入ABEntry构造函数本体的时间更早)。numTimeConsulted例外,因为是内置类型。
规则三 member initialization list(成员初值列)替换赋值操作
ABEntry::ABEntry(const std::string& name, const std::string& address, const std::list<PhoneNumber>& phones)
: theName(name),
theAddress(address), // 现在,这些都是初始化(initialization)
thePhones(phones),
numTimeConsulted(0)
{ } // 现在,构造函数本体不必做任何动作
这个构造函数和上一个的最终结果都相同,但通常效率较高。因为赋值那个版本首先调用default构造函数为theName, theAddress和thePhones设初值,然后立刻再对它们赋予新值。default构造函数的一切动作因此浪费了。第二版避免了这个问题,因为初值列中针对各个成员变量而设的参数,被拿出作为各成员变量之构造函数的实参。theName以Name为初值进行copy构造,对于内置类型,其初始化和赋值的成本相同,但是为了一致最好也通过成员初值列来初始化。 同样道理,甚至当你想要default构造一个成员变量,你都可以使用成员初始值,只要指定无物作为初始化实参即可。
ABEntry::ABEntry()
:theName(), // 调用theName的default构造函数
theAddress(),
thePhones(),
numTimesConsulted(0) // 记得将numTimesConsulted显式初始化为0
{}
规则四 C++有着十分固定的"成员初始化次序"
base classes更早于其derived classes被初始化,而class的成员变量总是以其声明次序被初始化,即使在成员初值列中以不同的次序出现,夜不会有任何影响。
规则五 “不同编译单元内定义之non-local static对象”的初始化次序
所谓static对象,其寿命从被构造出来直到程序结束为止,因此stack和heap-based对象都被排除。
函数内的static对象称为local static对象(因为它们对函数而言是local),其他static对象称为non-local static对象。
程序结束时static对象会被自动销毁,也就是它们的析构函数会在main()结束时被自动调用。
所谓编译单元是指产出单一目标文件的那些源码。基本上它是单一源码文件加上其他含入的头文件。
C++对“定义于不同编译单元内的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。然而,C++对“定义于不同的编译单元内的non-local static对象”的初始化相对次序并无明确定义。
规则六 non-local static 对象被local static对象替换
class FileSystem { ... };
FileSystem& tfs() {
static FileSystem fs;
return fs;
}
class Directory { ... };
Directory::Directory( params ) {
...
std::size_t disks = tfs().numDisks();
...
}
Directory& tempDir() {
static Directory td;
return td;
}
以上设计,如果再把它们的构造函数设置为private的话,就是一种Singleton设计模型
总结
- 对内置类型对象进行手工初始化,因为C++不保证初始化它们。
- 构造函数最好使用成员初值列,而不要再构造函数本体内使用赋值操作。初值列列出的成员变量,其排列次序应该和它们在class中的声明次序相同。
- 为免除“跨编译单元之间初始化次序“问题,请以local static 对象替换non-local static对象。
Effective C++ 条款04:确定对象被使用前已经先被初始化的更多相关文章
- Effective C++ -----条款04:确定对象被使用前已被初始化
为内置型对象进行手工初始化,因为C++不保证初始化它们. 构造函数最好使用成员初值列,而不要在构造函数本体内使用赋值操作.初值列列出的成员变量,其排列次序应该和它们在class中的声明次序相同. 为免 ...
- EC读书笔记系列之2:条款4 确定对象被使用前已先被初始化
条款4:确定对象被使用前已先被初始化 记住: ★为内置对象进行手工初始化,因为C++不保证初始他们 ★构造函数最好使用初始化列表,而不要在构造函数本体内使用赋值操作.初始化列表列出的成员变量,其排列次 ...
- [effictive c++] 条款04 确定对象被使用前已被初始化
成员初始化 在c和c++ 中,使用为初始化的类型经常会引发不可预料的错误,从而使得我们要花费巨大的时间用于调试查找问题,所以确定对象被使用前已被初始化是个非常好的习惯. 永远在使用之前对对象进行初始化 ...
- Effective C++ 条款四 确定对象被使用前已被初始化
1.对于某些array不保证其内容被初始化,而vector(来自STL)却有此保证. 2.永远在使用对象前初始化.对于无任何成员的内置类型,必须手工完成. int x = 0; c ...
- [Effective C++ --009]确定对象被使用前已先被初始化
在确保对象在使用前已先被初始化这一条款的编码实践中,作者为我们总结了三条经验,它们分别是: ------------------------------------------------------ ...
- Effective C++ 之 Item 4:确定对象被使用前已先被初始化
Effective C++ Chapter 1. 让自己习惯C++ (Accustoming Yourself to C++) Item 4. 确定对象被使用前已先被初始化 (Make sure th ...
- 读书笔记 effective c++ Item 4 确保对象被使用前进行初始化
C++在对象的初始化上是变化无常的,例如看下面的例子: int x; 在一些上下文中,x保证会被初始化成0,在其他一些情况下却不能够保证.看下面的例子: class Point { int x,y; ...
- Effective C++学习笔记 条款04:确定对象被使用前已先被初始化
一.为内置类型对象进行手工初始化,因为C++不保证初始化它们. 二.对象初始化数据成员是在进入构造函数用户编写代码前完成,要想对数据成员指定初始化值,那就必须使用初始化列表. class A { pu ...
- Effective C++ -----条款12: 复制对象时勿忘其每一个成分
Copying函数应该确保复制“对象内的所有成员变量”及“所有base class成分”. 不要尝试以某个copying函数实现另一个copying函数.应该将共同机能放进第三个函数中,并由两个cop ...
随机推荐
- 禁用chrome默认打印框直接打印
在做web打印的时候 重要弹出一个对话框选择打印机等等, 比较影响操作, 经过一番谷歌终于找到了解决方案 在桌面的chrome 图标 右键 打开属性对话框 在目标 添加 --kiosk-printi ...
- SpringMVC如何接收json数据
请求头:Content-Type=application/json数据如: {"mobile":"12345678912","smsContent&q ...
- git、git bash、git shell的区别
之前安装了github(CSDN上找的,官网的下不来,貌似要FQ - -)后,自带了git shell,如图: 输命令的时候发现网上的一些命令不管用,譬如:git ls –a 查看隐藏的 .git 文 ...
- 170117、spring解决乱码
spring解决乱码这个问题网上有很多解决方法,也可以关注本博客的文章,在此不再赘述, 今天推荐大家另外两种解决方法! 问题现象: 1.后台代码 2.前端界面 解决方法: 方法1:是在后台请求方法上加 ...
- Instagram发布动态自动裁剪照片说明
发布Ins时,照片总是被截取一截,感觉很不爽...然后就仔细了解了Ins是如何限制图片大小的. 官方帮助说的很清楚,https://help.instagram.com/163182164042672 ...
- JDK源码分析之concurrent包(三) -- Future方式的实现
上一篇我们基于JDK的源码对线程池ThreadPoolExecutor的实现做了分析,本篇来对Executor框架中另一种典型用法Future方式做源码解读.我们知道Future方式实现了带有返回值的 ...
- Career Planning:Developers Best Practices Tutorial
This small tutorial is based on my past 16+ years of experience in software development industry. I ...
- CMDB初步了解
本节内容 浅谈ITIL CMDB介绍 Django自定义用户认证 Restful 规范 资产管理功能开发 浅谈ITIL TIL即IT基础架构库(Information Technology Infra ...
- pandas 修改指定列中所有内容
如下图: 读取出来的 DataFrame “code” 列内容格式为:“浪潮信息(000977.XSHE)” 格式,目标效果是:000977.XSHE 代码: df["code"] ...
- HDU1838:Chessboard(线性dp)
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1838 这题也挺不错的.首先题目说了,棋盘的右下角一定是'1',另外棋盘里面至少包含一个1,所以最小值是1, ...