欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Effective C++ 条款总结

程序员文章站 2022-07-12 17:52:04
...


自己在看这本书的时候,回去翻看目录的时候,有些规则会被遗忘,因此做个简单的小总结供自己和其他人参考,没读过的还是要先去读一遍的

一、让自己习惯C++

1 视C++为一个语言联邦

C++是一种包含许多特性的语言,因而不要把它视为一个单一语言。理解C++至少需要学习一下4个部分:

  • C语言。C++仍以C为基础
  • objected-oriented C++。面向对象编程,类、封装、继承、多态
  • template C++。C++泛型编程、模板元编程的基础
  • STL。容器、迭代器、算法

2 尽量使用const等替换#define

  • 对于单纯常量,最好以const或者enums替换#define
  • 对于形似函数的宏(macros),最好改用inline函数替换

3 尽可能使用const

  • const可以作用于:变量、指针、函数参数类型、类中的常函数。const可以防止变量被意外的修改,有助于编译器检测这些意外改变。
  • 当non-const和const实现相同逻辑时,non-const对象可以调用const成员函数,这样可以缩减代码量。另外注意const对象不能调用non-const成员函数,编译报错:discards qualifiers。
  • const类型 迭代器,指针不能变;const_iterator类型,指针可以变,所指向的值不变:
const vector<int>::iterator it;
it++;错误
*it=10;正确

vector<int>::const_iterator it;
it++;正确
*it=10;错误

4 确定对象使用前被初始化

在构造函数的初始化列表中的才算是初始化,而构造函数的内容是在初始化列表之后执行的,已经不算是初始化操作。这里就存在效率问题。

假设你的类成员是个其他类的对象,比如std::string name,你在初始化列表中进行初始化,调用的是string的拷贝构造函数,而在构造函数中进行赋值的话,调用的是:默认构造函数+赋值函数,调用默认构造的原因是,调用构造函数之前会先对成员进行初始化(这也就是为什么在构造函数中进行的操作不能称之为初始化操作),而对于大多数类,默认构造函数+赋值函数的效率是小于只调用拷贝构造函数的。

  • 内置类型要手动初始化,不同的平台不能保证对内置类型进行初始化
  • 因此最好是在初始化列表中进行初始化操作。
  • 为避免“夸编译单元初始化次序”,以local static对象替换non-local static对象。

二、构造/析构/赋值运算

5 C++默认编写并调用的函数

  • 编译器默认实现的函数:默认构造、析构、拷贝构造、赋值函数。这里注意深拷贝和浅拷贝问题。①对类内引用型数据对象进行赋值操作,必须定义拷贝赋值函数;②某个基类将拷贝赋值函数声明为private,则编译器对派生类不能生成该函数。

6 不想使用默认生成的函数,可以明确拒绝

  • 默认的构造可以被其他构造替换,拷贝构造和赋值函数如果不想被外面调用可以将其声明为private。(member函数与friend函数仍然可以调用private函数,但是会获得连接错误)
  • 不想被复制,也可以设计基类,其中基类的复制构造函数和赋值函数均为private类型,则派生类的对象,可以避免被复制。(但可能会导致多重继承)

7 多态基类声明virtual析构函数

  • 当一个父类指针指向子类对象时(即多态的用法),在释放对象时,如果父类的析构函数不是virtual的,那么编译器会将这个指针视为父类类型的,只会释放掉这个对象的一部分空间。如果声明为virtual的,那么在释放的时候,编译器就知道这是一个子类类型,会将对象都释放掉,即防止内存泄漏问题。
  • 此处涉及虚表指针和虚函数表
  • 当类内含有至少一个virtual函数时,声明为virtual析构函数
  • 纯虚析构函数,必须进行一份定义。子类继承父类,析构函数的运行方式是,最深处的子类的析构被调用,然后是每个基类的析构函数被调用
  • 并非所有基类的设计都是为了多态,如6中,设计带有private的基类为了避免子类被复制。

8 别让异常逃离析构函数

  • 绝不要让析构函数抛出异常,应该让用户自己处理可能发生异常的操作
    解决办法①:调用absort()
    解决办法②:析构中吞下因调用函数而发生的异常(try…catch)
    或者说,重新设计函接口,对可能出现的问题做出反应。

9 不要在构造和析构函数调用virtual函数

10 令operator=返回reference to *this 并 11处理自我赋值

①这么写,没毛病,返回引用比临时变量要少几次构造析构,效率高
 ②第二条是因为,赋值的时候要先释放自己的资源然后赋予新的资源(资源假设为一个指针,这样便于理解),如果你自己给自己赋值,按照这个先释放再赋值的逻辑,自己直接就没了。

  • 所以发现是自己赋值自己的时候(this = &object)直接返回*this即可。
Widget& operator=(const Widget& rhs)
{
	...
	return* this;
}

11 在operator=中处理“自我赋值”

  • 确保当对象自我赋值时,operator=的行为良好,技术包括“来源对象”和“目标对象”的地址、精心周到的语句顺序、以及copy-and-swap
  • 确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为依然正确。

12 复制对象时勿忘其每一个成分

9/12、深浅拷贝

相关标签: C++