C ++ 11中自动生成特殊移动函数(构造函数和赋值运算符)的规则指定不能声明析构函数。据推测,如果你需要在破坏方面做一些特别的事情,那么这一举动可能并不安全。
但是,对于多态中适当的析构函数调用,必须声明一个基类'析构函数为虚拟(否则通过其基类的指针删除子类的实例将无法正确链接析构函数)。
我假设,即使是空的析构函数也会阻止编译器自动生成特殊的移动函数。如:
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没有任何问题,但这会破坏以下"客户端"代码:
class Sub : public Base {
virtual ~Sub(); // this declaration is now "looser" because of no noexcept
}
所以问题2更重要的是:有没有办法允许在C ++ 11中自动生成特殊的移动函数,并允许正确的析构函数链接到子类(如上所述),所有这些都不会破坏子类(&# 34;客户")代码?
答案 0 :(得分:18)
不,默认的析构函数仍然被认为是用户定义的,因此它将阻止生成移动操作。同时声明移动操作default
- ed以使编译器生成它们。
您只需将移动操作声明为default
- 在基类中编辑。在派生类中,析构函数不再是用户定义的(除非您明确说明),因此不会删除移动操作。
所以我要做的是以下内容:
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的优秀书籍 Effective Modern的项目17:理解特殊成员函数生成 C ++ 。这个问题得到了很好的解释。
PS:我认为你应该多考虑一下你的基类。大多数情况下,您应该使用抽象类,因此不需要复制/移动它们的实例。
PSS:我认为默认情况下,析构函数在C ++ 11/14中标记为noexcept
,因此不明确指定它不会导致任何问题:
继承构造函数和隐式声明的默认值 构造函数,复制构造函数,移动构造函数,析构函数, 复制赋值运算符,移动赋值运算符都是 除非需要调用函数,否则默认情况下为noexcept(true) 这是noexcept(false),在这种情况下这些函数是 noexcept(假)。