受帖子 Why does destructor disable generation of implicit move methods? 的启发,我想知道默认的虚拟析构函数是否也是如此,例如
class WidgetBase // Base class of all widgets
{
public:
virtual ~WidgetBase() = default;
// ...
};
由于该类旨在成为窗口小部件层次结构的基类,因此我必须定义其析构函数virtual,以避免在使用基类指针时出现内存泄漏和未定义的行为。另一方面,我不想阻止编译器自动生成移动操作。
默认的虚拟析构函数是否会阻止编译器生成的移动操作?
答案 0 :(得分:25)
是的,声明任何析构函数都会阻止移动构造函数的隐式声明。
时默认为
N3337 [class.copy]/9:
如果类X的定义没有显式声明一个移动构造函数,那么将隐式声明一个 当且仅当
- X没有用户声明的复制构造函数,
- X没有用户声明的复制赋值运算符
- X没有用户声明的移动赋值运算符
- X没有用户声明的析构函数和
- 移动构造函数不会被隐式定义为已删除。
声明析构函数并将其定义为default
计为用户声明的。
您需要声明移动构造函数并将其自己定义为default
:
WidgetBase(WidgetBase&&) = default;
请注意,这会将复制构造函数定义为delete
,因此您还需要default
那个:
WidgetBase(const WidgetBase&) = default;
复制和移动赋值运算符的规则也非常相似,因此如果需要,您必须default
。
答案 1 :(得分:0)
不是解决方案,而是可能的解决方法之一。 您可以从仅具有默认虚拟析构函数的类继承所有类。
我使用GCC 9和Apple的Clang ++和-std=c++17
进行了检查:两者都为继承以下类的类生成了移动构造函数。
class Object {
public:
virtual ~Object() = default;
};
下面的类确实将具有move构造函数。
class Child : public Object {
public:
Child(std::string data) : data(data) {
}
private:
std::string data;
};
另一个可能但有风险的解决方法是根本不声明虚拟析构函数。它将带来以下风险:
std::vector
或std::list
之类的容器中时,必须始终使用std::shared_ptr
进行包装。 std::unique_ptr
会导致泄漏!这与它们与存储删除器的区别有关。