详解在C++中显式默认设置的函数和已删除的函数的方法

2020-01-06 14:32:52王冬梅
  • 如果显式声明了复制赋值运算符或析构函数,则弃用复制构造函数的自动生成。
  • 在这两种情况下,Visual Studio 将继续隐式自动生成所需的函数且不发出警告。

    这些规则的结果也可能泄漏到对象层次结构中。例如,如果基类因某种原因无法拥有可从派生类调用的默认构造函数 - 也就是说,一个不采用任何参数的 public 或 protected 构造函数 - 那么从基类派生的类将无法自动生成它自己的默认构造函数。

    这些规则可能会使本应直接的内容、用户定义类型和常见 C++ 惯例的实现变得复杂 — 例如,通过以私有方式复制构造函数和复制赋值运算符,而不定义它们,使用户定义类型不可复制。

    
    struct noncopyable
    {
     noncopyable() {};
    
    private:
     noncopyable(const noncopyable&);
     noncopyable& operator=(const noncopyable&);
    };
    
    

    在 C++11 之前,此代码段是不可复制的类型的惯例形式。但是,它具有几个问题:
    复制构造函数必须以私有方式进行声明以隐藏它,但因为它进行了完全声明,所以会阻止自动生成默认构造函数。如果你需要默认构造函数,则必须显式定义一个(即使它不执行任何操作)。
    即使显式定义的默认构造函数不执行任何操作,编译器也会将它视为重要内容。其效率低于自动生成的默认构造函数,并且会阻止 noncopyable 成为真正的 POD 类型。
    尽管复制构造函数和复制赋值运算符在外部代码中是隐藏的,但成员函数和 noncopyable 的友元仍可以看见并调用它们。如果它们进行了声明但是未定义,则调用它们会导致链接器错误。
    虽然这是广为接受的惯例,但是除非你了解用于自动生成特殊成员函数的所有规则,否则意图不明确。
    在 C++11 中,不可复制的习语可通过更直接的方法实现。

    
    struct noncopyable
    {
     noncopyable() =default;
     noncopyable(const noncopyable&) =delete;
     noncopyable& operator=(const noncopyable&) =delete;
    };
    

    请注意如何解决与 C++11 之前的惯例有关的问题:
    仍可通过声明复制构造函数来阻止生成默认构造函数,但可通过将其显式设置为默认值进行恢复。
    显式设置的默认特殊成员函数仍被视为不重要的,因此性能不会下降,并且不会阻止 noncopyable 成为真正的 POD 类型。
    复制构造函数和复制赋值运算符是公共的,但是已删除。定义或调用已删除函数是编译时错误。