将仅移动类型添加到 class 会使 class 成为仅移动类型?

Adding a move only type to a class makes that class as a move only type?

在 Scott Meyers 的 "Effective Modern C++" 中,他写道:

It's worth nothing that because std::mutex is a move-only type (i.e., a type that can be moved, but not copied), a side effect of adding m to Polynomial is that Polynomial loses the ability to be copied. It can still be moved, however.

在这里,他在解释为什么要保护对 [=27 的 const 成员变量的访问时,将 std::mutex m 作为成员变量添加到 class Polynomial =](多线程时)。我理解他解释的概念。但是我需要更多解释的一件事是 "why Adding a move only type to a class makes that class as move only type not copy-able"?,为什么像 std::mutexstd::atomic 这样的类型在默认情况下是仅移动类型?如果我们想要执行复制操作,即使在向我们的 class 添加仅移动类型的变量时,我们如何克服它?

"why Adding a move only type to a class makes that class as move only type not copy-able"

这不完全正确。添加不可复制的成员变量会阻止您编写类似 Type (const Type& t) = default; 的内容,但您仍然可以实现自己的复制构造函数,它会忽略不可复制的成员

class Type{

int integer;
std::mutex m;

public:
Type() = default;
Type(const Type& rhs): integer (rhs.integer){}

}

除此之外,您可以找到许多包含仅移动成员的对象示例,但它们本身是不可移动的,原因很简单,因为开发人员删除了移动构造函数。

why types like std::mutex and std::atomic is move only type by default?

它们都没有实现移动构造函数。这是一个错误的说法。

一种可能是将互斥量类型更改为指向互斥量的指针。您可以复制指针,但仍然只有一份互斥量。您可能需要使用智能指针。

std::mutex 不可复制只是因为标准是这样说的。他们本来可以写一个可复制的 std::mutex,但他们决定不这样做。

作为猜测,不可复制的 std::mutex 可能更有效、更安全或更容易理解。

举个例子,这里是为什么可能safer/easier要理解:复制一个被锁定的std::mutex是什么意思?我个人不知道正确答案是什么;我怀疑正确答案是 "that is nonsense"。没有"answer of least surprise".

通过阻止复制,我们避免了这个问题,而不是在并发代码中得到一个令人惊讶的答案。存储想要复制的互斥锁的人必须自己决定他们想要它做什么。


C++在某些情况下会自动生成拷贝构造函数。在更多情况下它会让你做MyClass(MyClass const&)=default并在你要求时写一个

如果您的 class 包含一个不可复制的 class,它不会生成一个,您也不能请求它。这是因为生成的复制构造函数基本上复制了它的成员;如果你不能复制一个成员,它就不能生成一个复制构造函数。


所以mutex不能复制,因为标准是这么说的。

如果结构或class包含不可复制的成员,则不能使用默认的复制构造函数。你必须明确地自己写一个。


如果您的类型需要存储 mutex,一种避免必须维护手动复制其所有其他成员的复制构造函数的方法是将您的非 mutex state 到一个子结构中,然后使用它的默认副本。然后你决定在复制过程中如何处理 mutex,并且你的复制构造函数(和赋值复制运算符)保持简单。

struct bob_with_mutex {
  sturct bob_simple_data {
    int x, y, z;
    std::vector<char> buff;
  };

  bob_simple_data data;
  std::mutex m;

  bob_with_mutex( bob_with_mutex const& o ):
    data(o.data)
  {}
  bob_with_mutex& operator=( bob_with_mutex const& o )
  {
    data = o.data;
    return *this;
  }
};

类型 bob 混合了互斥量和一些数据。数据存储在子结构中。 bob_with_mutex 的复制构造函数不能默认,但它只是说 "copy the data, and nothing else".

bob 的副本有自己的互斥量。