1

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

毫无价值,因为std::mutex它是只移动类型(即可以移动但不能复制的类型),添加mto的副作用PolynomialPolynomial失去被复制的能力。但是,它仍然可以移动。

在这里,他在解释为什么应该保护对类的 const 成员变量的访问(在多线程时)的上下文中将astd::mutex m作为成员变量添加到类中。Polynomial我理解他解释的概念。但是我需要更多解释的一件事是“为什么向类添加仅移动类型会使该类成为仅移动类型不可复制”?为什么默认类型为仅移动类型std::mutexstd::atomic即使在向我们的类中添加仅移动类型的变量时,如果我们想要执行复制操作,我们如何才能克服它?

4

3 回答 3

2

“为什么向类添加仅移动类型会使该类成为仅移动类型不可复制”

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

class Type{

int integer;
std::mutex m;

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

}

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

为什么像 std::mutex 和 std::atomic 这样的类型默认是只移动类型?

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

于 2016-03-29T13:06:08.410 回答
1

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

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

例如,这就是为什么它可能更安全/更容易理解的原因:复制std::mutex被锁定的对象是什么意思?我个人不知道正确答案是什么;我怀疑正确的答案是“那是胡说八道”。没有“最不意外的答案”。

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


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

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


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

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


如果您的类型需要存储 a mutex,一种避免必须维护手动复制其所有其他成员的复制 ctor 的麻烦的方法是将您的非mutex状态粘贴到子结构中,然后使用其默认副本。然后,您决定mutex在复制期间如何处理 ,并且您的复制 ctor(和赋值复制运算符)保持简单。

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混合了互斥锁和一些数据。数据存储在子结构中。的复制 ctorbob_with_mutex不能默认,但它只是说“复制数据,仅此而已”。

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

于 2016-03-29T13:44:49.077 回答
-1

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

于 2016-03-29T13:17:39.513 回答