细读 Effective C++

深入 C++ 的诸多设计细节,了解实际场景的最佳实践,以面向对象的方式重新认识 C++。

Effective C++ 52:写了 placement new 就要写 placement delete

Effective-C++ C++ 异常 指针 动态内存 名称隐藏 构造函数

new和delete是要成对的,因为当构造函数抛出异常时用户无法得到对象指针,因而delete的责任在于C++运行时。 运行时需要找到匹配的delete并进行调用。因此当我们编写了"placement new"时,也应当编写对应的"placement delete", 否则会引起内存泄露。在编写自定义new和delete时,还要避免不小心隐藏它们的正常版本。

Effective C++ 51:写 new 和 delete 时请遵循惯例

Effective-C++ C++ 异常 指针 数组 动态内存 析构函数

new需要无限循环地获取资源,如果没能获取则调用"new handler",不存在"new handler"时应该抛出异常; new应该处理size为零的情况; delete应该兼容空指针; new/delete作为成员函数应该处理size > sizeof(Base)的情况(因为继承的存在)。

Effective C++ 48:了解模板元编程

Effective-C++ C++ 模板 traits 编译 模板元编程

模板元编程(Template Metaprogramming,TMP)就是利用模板来编写那些在编译时运行的C++程序。模板元程序(Template Metaprogram)是由C++写成的,运行在编译器中的程序。当程序运行结束后,它的输出仍然会正常地编译。

Effective C++ 44:将参数无关代码重构到模板外去

Effective-C++ C++ 内存 多态 模板

把模板中参数无关的代码重构到模板外便可以有效地控制模板产生的代码膨胀。另外代码膨胀也可以由类型模板参数产生:对于非类型模板参数产生的代码膨胀,用函数参数或数据成员来代替模板参数即可消除冗余;对于类型模板参数产生的代码膨胀,可以让不同实例化的模板类共用同样的二进制表示。

Effective C++ 40:明智地使用多继承

Effective-C++ C++ 多继承 接口类 名称隐藏 对象组合

多继承比单继承复杂,引入了歧义的问题,以及虚继承的必要性;虚继承在大小、速度、初始化/赋值的复杂性上有不小的代价,当虚基类中没有数据时还是比较合适的;多继承有时也是有用的。典型的场景便是:public继承自一些接口类,private继承自那些实现相关的类。

Effective C++ 35:考虑虚函数的其他替代设计

Effective-C++ C++ 策略模式 模板方法 虚函数 函数指针

非虚接口范式(NVI idiom)可以实现模板方法设计模式。用函数指针代替虚函数,可以实现策略模式。用function代替函数指针,可以支持所有兼容目标函数签名的可调用对象。用另一个类层级中的虚函数来提供策略,是策略模式的惯例实现。

Effective C++ 27:最小化类型转换

Effective-C++ C++ 类型转换 运算符重载 类型检查

C++的类型检查只在编译时执行,运行时没有类型错误的概念。理论上讲只要你的代码可以编译那么就运行时就不会有不安全的操作发生。但C++允许类型转换,也正是类型转换破坏了理论上的类型系统。

Effective C++ 25:考虑实现一个不抛异常的 swap

Effective-C++ C++ STL 异常 模板 特化 作用域 函数重载

提供一个更加高效的,不抛异常的公有成员函数(比如 `Widget::swap`)。在你类(或类模板)的同一命名空间下提供非成员函数 `swap`,调用你的成员函数。如果你写的是类而不是类模板,请偏特化 `std::swap`,同样应当调用你的成员函数。调用时,请首先用 `using` 使 `std::swap` 可见,然后直接调用 `swap`。

Effective C++ 20:传递常量引用比传值更好

Effective-C++ C++ 引用 常量

Item 20: Prefer pass-by-reference-to-const to pass-by-value C++函数的参数和返回值默认采用传值的方式,这一特性是继承自 C 语言的。如果不特殊指定, 函数参数将会初始化为实参的拷贝,调用者得到的也是返回值的一个副本。 这些拷贝是通过调用对象的拷贝构造函数完成的,正是这一方法的调用使得拷贝的代价可能会很高。 通常来讲,传递常量引用比传值更好,同时避免了截断问题。但是内置类型和 STL 迭代器,还是传值更加合适。

Effective C++ 19:把类的设计视作类型设计

Effective-C++ C++ 接口 类型 设计

在面向对象语言中,开发者的大部分时间都用在了增强你的类型系统。这意味着你不仅是类的设计者,更是类型设计者。重载函数和运算符、控制内存分配和释放、定义初始化和销毁操作……良好的类型有着自然的语法、直观的语义,以及高效的实现。你在定义类时需要像一个语言设计者一样地小心才行!

Effective C++ 12:完整地拷贝对象

Effective-C++ C++ 继承 拷贝构造函数 构造函数 赋值运算符

在一个成熟的面向对象的C++系统中,只有两种拷贝对象的方式:复制构造函数和赋值运算符。当重载拷贝函数时,首先要完整复制当前对象的数据(local data);然后调用所有父类中对应的拷贝函数。