使类不可复制*和*不可移动

Posted

技术标签:

【中文标题】使类不可复制*和*不可移动【英文标题】:Make a class non-copyable *and* non-movable 【发布时间】:2016-01-10 20:22:18 【问题描述】:

在 C++11 之前,我可以使用它来使类不可复制:

private:
MyClass(const MyClass&);
MyClass& operator=(const MyClass&);

使用 C++11,我可以这样做:

MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;

当使用带有已删除副本和赋值的类时,是否有可能生成默认的移动运算符?而且这个类并没有完全复制,而是移动了(有点相似)?

那么,我是否必须这样做以防止默认移动构造和分配:

MyClass(MyClass&&) = delete;
MyClass& operator=(MyClass&&) = delete;

... ?

【问题讨论】:

你不需要它。就我个人而言,无论如何我将这样的东西放入一个名为NoCopyOrMove 的私有基类中,所以它不会弄乱我的代码。 MyClass(MyClass&&) = delete; 将隐式禁用其他人 【参考方案1】:

正如其他人在 cmets 中已经提到的,已删除的构造函数是在 C++11 中引入的。为了回答您的问题,一般遵循以下规则:

    两个复制操作是独立的。声明复制构造函数不会阻止编译器生成复制赋值,反之亦然。 (与 C++98 相同) 移动操作不是独立的。声明其中一个会阻止编译器生成另一个。 (不同于复制操作。) 如果声明了任何复制操作,则不会生成任何移动操作。 (您的情况。) 如果声明了任何移动操作,则不会生成任何复制操作。这是与之前相反的规则。 如果声明了析构函数,则不会生成任何移动操作。仍会生成复制操作以与 C++98 反向兼容。 仅在未声明构造函数时生成默认构造函数。 (与 C++98 相同)

根据 cmets 的要求,这里有一些来源(C++11 是草稿 N3242):

复制操作:§ 12.8.8, § 12.8.19 移动操作:§ 12.8.10, § 12.8.21 默认构造函数:§ 12.1.5

【讨论】:

你从哪里得到这些事实的? 这是我的知识 :) 对于您的要求,我扩展了我的答案,并在 C++ 标准中添加了一些引用来支持它。 规则 4 与规则 3 在什么意义上相反? @FrancescoBoi:如果你声明了一个复制操作,那么移动操作就不会产生,反之亦然。【参考方案2】:

声明复制构造函数时不会生成移动构造函数/赋值。

所以

MyClass(MyClass&&) = delete;
MyClass& operator=(MyClass&&) = delete;

不是必需的。

您仍然可以将其添加得更明确。

【讨论】:

明确是好的:我总是声明所有运算符,并选择性地delete 那些我不需要的。它使我的意图清晰,以防万一存在编译器错误,它仍应按我预期的方式工作。

以上是关于使类不可复制*和*不可移动的主要内容,如果未能解决你的问题,请参考以下文章

为啥 c++ 线程是可移动的但不可复制的?

Initializer-list-构造一个不可复制(但可移动)对象的向量

通过定义默认私有构造函数使类不可继承

保证复制省略和不可移动Nonmoveable

如果 lambda 使用 std::move() 捕获不可复制的对象,为啥它是不可移动的?

不使用聚合初始化直接初始化不可复制、不可移动的成员