C++11 虚拟析构函数和 move 特殊函数的自动生成

标签 c++ c++11 inheritance move-semantics

C++11 中自动生成特殊 move 函数(构造函数和赋值运算符)的规则规定不能声明析构函数。逻辑大概是,如果你需要做一些特殊的破坏,那么这个 Action 可能并不安全。

但是,为了在多态中正确调用析构函数,必须将基类的析构函数声明为虚拟(否则通过基类的指针删除子类的实例将无法正确链接析构函数)。

然后,我假设即使是空的析构函数也会阻止编译器自动生成特殊的 move 函数。如:

class Base {
    virtual ~Base() { }
};

但是,您可以默认析构函数,如下所示:

class Base {
    virtual ~Base() = default;
}

那么问题 1:这是否允许编译器自动生成特殊 move 函数?

但是,显式默认析构函数存在问题。至少在 GCC 4.8.2 的情况下,签名被隐式更改为 noexcept。如:

class Base {
    virtual ~Base() = default; // compiler changes to:
    // virtual ~Base() noexcept;
}

虽然我对析构函数中的 noexcept 没有任何问题,但这会破坏以下“客户端”代码:

class Sub : public Base {
    virtual ~Sub(); // this declaration is now "looser" because of no noexcept
}

所以问题 2 更重要的是:有没有办法允许在 C++11 中自动生成特殊 move 函数并允许适当的析构函数链接到子类(如上所述),所有这些都不会破坏子类(“客户端") 代码?

最佳答案

  1. 不,默认的析构函数仍然被认为是用户定义的,所以它会阻止 move 操作的生​​成。还要声明 move 操作 default-ed 以使编译器生成它们。

  2. 您只需要在基类中将 move 操作声明为 default-ed。在派生类中,析构函数将不再由用户定义(除非您明确说明),因此不会删除 move 操作。

所以我要做的是:

class Base
{
    virtual ~Base() = default;
    Base(Base&&) = default;
    Base& operator=(Base&&) = default;
    // probably need to think about copy operations also, as the move disables them
    Base(const Base&) = default;
    Base& operator=(const Base&) = default;
};

我强烈推荐这个可能对 move 语义贡献最大的人的演讲:http://www.slideshare.net/ripplelabs/howard-hinnant-accu2014

或者,如果你能动手,你应该阅读 Scott Meyers 的优秀著作 Effective Modern 中的第 17 条:理解特殊成员函数生成 C++。这个问题解释得很好。

PS:我认为你应该多考虑一下你的基类。大多数时候,您应该使用抽象类,因此无需复制/move 它们的实例。

PSS:我认为默认情况下,析构函数在 C++11/14 中被标记为 noexcept,因此不明确指定它不会导致任何问题:

Inheriting constructors and the implicitly-declared default constructors, copy constructors, move constructors, destructors, copy-assignment operators, move-assignment operators are all noexcept(true) by default, unless they are required to call a function that is noexcept(false), in which case these functions are noexcept(false).

关于C++11 虚拟析构函数和 move 特殊函数的自动生成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29289956/

相关文章:

java - OOPS概念调用父类而不是子类的函数

ios - 从 C++ 类继承 NSObject

java - 重写 equals() 方法以检查共享继承的对象中的维度相等性

c++ - 用另一个数组初始化指向数组的指针的点

c++ - 为什么 clang++ 比 adc 更喜欢 adcx

c++ - 一起破解线程安全 'best' 行动方案吗?

c++ - 尽管编译了库的通用版本和 i386 版本,但未找到体系结构 i386 的符号

c++ - 访问对象void pointer c++的成员

c++ - 将误差条添加到 VTK 二维散点图

c++ - 运行时非多态容器