首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >C++11虚拟析构函数和move特殊函数的自动生成

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

Stack Overflow用户
提问于 2015-03-27 06:20:47
回答 1查看 4.7K关注 0票数 27

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

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

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

代码语言:javascript
复制
class Base {
    virtual ~Base() { }
};

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

代码语言:javascript
复制
class Base {
    virtual ~Base() = default;
}

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

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

代码语言:javascript
复制
class Base {
    virtual ~Base() = default; // compiler changes to:
    // virtual ~Base() noexcept;
}

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

代码语言:javascript
复制
class Sub : public Base {
    virtual ~Sub(); // this declaration is now "looser" because of no noexcept
}

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-03-27 06:22:52

  1. 否,默认的析构函数仍被视为用户定义的,因此它将阻止生成移动操作。
  2. 你只需要在基类中将移动操作声明为default-ed即可。在派生类中,析构函数将不再是用户定义的(除非您显式指定),因此不会删除移动操作。

所以我要做的是:

代码语言:javascript
复制
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 Meyer的优秀著作Effective C++中的第17项:理解特殊成员函数生成。这个问题得到了很好的解释。

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

我认为在默认情况下,C++11/14中的析构函数被标记为noexcept,所以不显式指定它应该不会造成任何问题:

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

票数 26
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29289956

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档