Why does std::copyable subsume std::movable?

use*_*147 8 c++ copy move-semantics c++20

According to cppreference, std::copyable is defined as follows:

template <class T>
concept copyable =
  std::copy_constructible<T> &&
  std::movable<T> && // <-- !!
  std::assignable_from<T&, T&> &&
  std::assignable_from<T&, const T&> &&
  std::assignable_from<T&, const T>;
Run Code Online (Sandbox Code Playgroud)

I'm wondering why a copyable object should be also movable. Just think about a global variable that is accessed by several functions. While it makes sense to copy that variable (for example to save its state before calling another function) it makes no sense, and actually would be very bad, to move it since other functions might not know that that variable is currently in an unspecified state. So why exactly does std::copyable subsume std::movable ?

bar*_*top 3

这来自两个事实。首先,即使您没有定义移动构造函数 + 移动赋值,如果您定义了复制函数,您仍然可以从右值引用构造/分配对象。看看这个例子:

#include <utility>

struct foo {
    foo() = default;
    foo(const foo&) = default;
    foo& operator=(const foo&) = default;
};

int main()
{
    foo f;
    foo b = std::move(f);
}
Run Code Online (Sandbox Code Playgroud)

其次(也许更重要的是),可复制类型始终可以(或根据现在的标准必须)以某种方式可移动。如果对象是可复制的,那么移动的最坏情况就是复制内部数据。

请注意,由于我声明了复制构造函数,编译器不会生成默认的移动构造函数。

  • 即使认为右值可以绑定到 const 左值,您发布的代码也可以工作,因为编译器_隐式_生成了移动构造函数。如果您显式删除它,代码将无法编译,您将得到一个可复制但不可移动的类型,这对于您解释的原因没有任何意义。看起来概念并不像类型特征那样关心每个特定情况,而且我们已经通过查看“is_convertible”和“convertible_to”、“is_default_constructible”和“default_initialized”等之间的差异看到了这一点...... (2认同)
  • @user7769147这是不正确的,如果存在用户定义的复制函数,编译器不会生成移动函数。显式删除只会使编译器忽略 r-val ref 到 const l-val ref 的转换 (2认同)
  • @user7769147我写了一个错误,我的意思是用户声明的复制构造函数会阻止移动构造函数的自动生成。这是用户声明的。 (2认同)
  • @user7769147:我同意巴托普的观点。该标准对用户声明与用户定义非常挑剔。即使特殊成员函数不是用户定义的,它仍然可以由用户声明(默认),在复制构造函数的情况下,这将禁用移动构造函数。 (2认同)