C++ 构造函数那些事: 三五〇法则

2020年02月01日 264点热度 0人点赞 0条评论

我们知道如果不提供默认/copy/copy-assignment构造函数,编译器会为我们自动生成相应的构造函数,那么在C++编程实践中,什么时候需要提供构造函数,什么时候要利用编译器的自动生成功能呢?大佬们总结为三五法则还有零法则。
C++ 中一个类有以下6种特殊的成员函数需要关注:

// https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#note-99
class X {
public:
    // ...
    X(); // default constructor
    virtual ~X();            // destructor (virtual if X is meant to be a base class)
    X(const X&);             // copy constructor
    X& operator=(const X&);  // copy assignment
    X(X&&);                  // move constructor
    X& operator=(X&&);       // move assignment
};
  • 以上六种特殊的成员函数可以声明为类似 X() = default 让编译器自动生成, 或者声明为 X() = delete 阻止编译器自动生成相应的函数定义
  • X::X() 默认构造函数 如果没有声明为 =delete,编译器将会自动生成定义。但是如果用户声明了其他形式的构造函数如X(int x) , 编译器将不会自动生成,除非用户手动定义。
  • X(const X&)X& operator=(const X&) 如果没有用户指定,在需要的时候编译器会自动生成,内容为对成员的值拷贝,如果是指针成员将是“浅复制”。
  • 对除 default ctor 之外的特殊成员函数的声明,哪怕是=defaultdelete,将会阻止编译器生成move constructor/assignment; 将会导致该类无法使用移动语义;
  • 如果手动声明了move constructor/assignment, 编译器隐式生成的复制和赋值语义将会声明为delete, 也就是class 将是 move-only 的。

Rule Of Three

如果需要自定义(user-defined)析构函数,自定义的copy 构造函数和自定义的 copy-assignment 操作符, 这三个往往同时需要自定义。

具体而言:需要对资源进行管理(例如raw pointer, POSIX 文件描述符)的时候,需要自己实现析构/复制/赋值构造函数, 编译器自动生成的往往是浅复制。

Rule of Five

Because the presence of a user-defined destructor, copy-constructor, or copy-assignment operator prevents implicit definition of the move constructor and the move assignment operator, any class for which move semantics are desirable, has to declare all five special member functions:

自定义(user-defined)析构函数,自定义的copy 构造函数或自定义的 copy-assignment 操作符的情况下,编译器不会生成默认的move构造函数和move-assignment 操作符。在这种情况下,如果需要移动语义,需要自己定义这5个特殊成员函数。

Rule of Zero

如果不需要手动定义, 就不要定义,一切让它默认。

Reference

  1. https://en.cppreference.com/w/cpp/language/rule_of_three
  2. Cpp Core Guide # C21

Charles

Stay hungry, stay foolish.

文章评论