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 函数并允许适当的析构函数链接到子类(如上所述),所有这些都不会破坏子类(“客户端") 代码?
最佳答案
不,默认的析构函数仍然被认为是用户定义的,所以它会阻止 move 操作的生成。还要声明 move 操作
default
-ed 以使编译器生成它们。您只需要在基类中将 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/