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

not*_*esh 21 c++ inheritance move-semantics c++11

C++ 11中自动生成特殊移动函数(构造函数和赋值运算符)的规则指定不能声明析构函数.据推测,如果你需要在破坏中做一些特别的事情,那么这一举动可能并不安全.

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

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

class Base {
    virtual ~Base() { }
};
Run Code Online (Sandbox Code Playgroud)

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

class Base {
    virtual ~Base() = default;
}
Run Code Online (Sandbox Code Playgroud)

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

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

class Base {
    virtual ~Base() = default; // compiler changes to:
    // virtual ~Base() noexcept;
}
Run Code Online (Sandbox Code Playgroud)

虽然我在析构函数中使用noexcept没有问题,但这会破坏以下"客户端"代码:

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

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

vso*_*tco 20

  1. 不,默认的析构函数仍然被认为是用户定义的,因此它将阻止生成移动操作.同时声明move操作default-ed以使编译器生成它们.

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

所以我要做的是以下内容:

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;
};
Run Code Online (Sandbox Code Playgroud)

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

或者,如果你能够掌握,你应该阅读第17项:了解 Scott Meyers的优秀书籍Effective Modern C++中的特殊成员函数生成.这个问题得到了很好的解释.

PS:我认为你应该多考虑一下你的基类.大多数情况下,您应该使用抽象类,因此不需要复制/移动它们的实例.

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

继承构造函数和隐式声明的默认构造函数,复制构造函数,移动构造函数,析构函数,复制赋值运算符,移动赋值运算符默认都是noexcept(true),除非它们需要调用noexcept函数(false) ,在这种情况下,这些函数是noexcept(false).

  • @stephelton找到了它,请看这里:http://stackoverflow.com/questions/11497252/default-destructor-nothrow (2认同)