什么是使类不可移动的用例(如果有的话)
what are use cases (if any) to make a class non-moveable?
考虑一种使类不可复制的经典方法:
// similar to boost::noncopyable
class noncopyable
{
protected:
constexpr noncopyable() = default;
noncopyable(const noncopyable&) = delete;
noncopyable& operator=(const noncopyable&) = delete;
};
class c: private noncopyable
{ /* ... */ };
由于声明任何复制操作都会阻止自动生成移动操作,因此这会自动使所有派生类也不可移动(默认情况下)(因此noncopyable
的全名为noncopyable_and_nonmoveable
)。
现在,让我们从标准库中查找经典的不可压缩类,例如unique_ptr
。它是不可复制的,但可以移动,否则它的实用性将受到限制。我想其他许多情况也是如此。
事实上,当一个类不可移动时,我想不出任何例子。我的论点是:即使一个班级没有被计划搬迁,也有一点可能是因为一个可能造成伤害的错误。
实际上是两个相关的问题:
1) 为什么boost::noncopyable
也是不可移动的?这会导致问题,请考虑:
struct c: private boost::noncopyable
{
std::unique_ptr<Something> something;
c(c&&) = default;
c& operator=(c&&) = default;
};
不起作用(wandbox)-不能生成移动操作,因为它们不是为基类生成的。您需要手动实现它们->列出您的成员->维护->bug。只要在noncopyable
中默认移动操作就可以解决问题。
2) 当可移动性是有害的,因此应该加以预防时,有哪些用例?
不可移动使您能够更好地控制对象标识。
如果一个物体是可移动的,它的地址可以改变:
moveonly a;
b = std::move(a);
现在,任何仍然引用a
的人都指向一个过时的对象或(完全是其他东西)。
出现这种情况的其他情况是,如果愿意,您有依赖于对象标识的外部逻辑("地址稳定性"),例如pthread互斥:移动std::mutex 的构造函数
附录-命名约定scoped_XXXX
经常用于暗示不可移动的类型(即保证不可变实例标识的类型)。与此形成对比的是,例如unique_XXXX
,它意味着一个独特的实例,可以四处移动注意但是,标准库并没有完全采用此命名约定:例如:std::lock_guard<>
与std::unique_lock<>
。C++17对此进行了一点修正
1)为什么boost::non-copyable也是不可移动的?
很可能是历史原因。boost::noncopyable
应该与C++11之前的编译器配合使用。在使用C++11及更高版本时,实际上没有什么理由继承boost::noncopyable
。如果它在C++11中是可移动的,我们如何在C++03编译器中建立相同的move语义?
2)当可移动性是有害的,因此应该加以预防时,有哪些用例?
不可移动性应适用于假定作为外部系统提供给您的各种资源,例如同步原语、表示计算机的ACPI平台等内容的对象等等。
为什么boost::noncopyable也是不可移动的
来自C++11标准:
如果类X的定义没有显式声明移动构造函数,则会隐式声明一个当且仅当
--X没有用户声明的复制构造函数
--X没有用户声明的副本分配运算符
--X没有用户声明的移动分配运算符
--X没有用户声明的析构函数,并且
--move构造函数不会被隐式定义为已删除。
所以,我想当您delete
您的复制c'tor和/或复制赋值时,您会阻止声明默认的移动构造函数。
当可移动性是有害的,因此应该加以预防时,有哪些用例
我首先想到的是依赖于它们在内存空间中的位置的对象,例如mutex
es。
- 仅包含可移动 std::map 的类的移动构造函数不起作用
- 如果可推导类型上有替换,可变参数模板类型推导会使编译器崩溃
- 为什么协程的返回类型必须是可移动构造的?
- 我应该使我的局部变量常量还是可移动的
- 对于参加可复制和可移动类的访问者来说,应该有多少过载?
- 如何获取类型是否真正可移动可构造
- 可移动但不可复制的对象:按值传递还是按引用传递?
- 对于可移动类型,按值传递比重载函数更好吗?
- 使用参数将仅可移动对象捕获到 lambda
- 具有抑制移动构造/赋值的类型如何仍被视为可移动类型?
- 防止作用域枚举可复制/可移动
- 在发布模式下崩溃,但如果可调试为 true - 不是..什么是可能的问题
- 禁止可移动的QGraphics物品与其他物品发生冲突
- 在向量中使用派生的可移动但不可压缩的会导致编译错误
- 在可移动类型的构造函数 lambda 中捕获此内容的安全使用
- 从类返回可移动成员变量
- 在成员容器中复制具有仅可移动但可克隆类型的构造函数
- 不可复制但可移动的容器
- 如果我移动一个值进行注册和编辑,它将有所作为
- 如果 T 不可移动,则 std::vector 是<T>可移动的吗?