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

C++11 virtual destructors and auto generation of move special functions

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

然而,为了在多态中正确调用析构函数,有必要将基 classes 的析构函数声明为虚拟的(否则通过其基指针删除子 class 的实例class 不会正确链接析构函数)。

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

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

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

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

所以问题 1:这会允许编译器自动生成特殊的移动函数吗?

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

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

虽然我对析构函数中的 noexcept 没有问题,但这会破坏以下 "client" 代码:

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

所以问题 2 更切题:有没有办法允许在 C++11 中自动生成特殊移动函数并允许适当的析构函数链接到子 classes(如上所述),所有这些都没有破坏 subclass ("client") 代码?

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

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

所以我要做的是:

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;
};

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

或者,如果您可以动手,您应该阅读来自 Scott Meyers 的项目 17:了解特殊成员函数生成 ' 优秀的书 Effective Modern C++。这个问题解释得很好。

PS:我认为你应该多考虑一下你的基础 classes。大多数时候,您应该使用抽象 classes,因此不需要 copy/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).