我很清楚这不是一个问题而是更多的讨论,但我相信可以提供一个或多个答案,所以你走了。
我有一个类似的课程
class MyAwesomeObject {
public:
std::mutex theListMutex;
std::list<int> theList;
};
现在,我相信这个意图是非常明显的,而且这个例子是有目的的学术性的 - 虽然距离我的现实还不远 - 所以让我们继续吧。然后我的应用程序处理大量这样的对象,所有这些对象都存储在其他地方的向量中,一切都很好。编译时麻烦就开始了。我正在使用VS2012,但我相信其他编译器可能会发出类似的错误:
error C2248: 'std::mutex::mutex' : cannot access private member declared in class 'std::mutex'
1> c:\program files\microsoft visual studio 11.0\vc\include\mutex(116) : see declaration of 'std::mutex::mutex'
1> c:\program files\microsoft visual studio 11.0\vc\include\mutex(107) : see declaration of 'std::mutex'
1> This diagnostic occurred in the compiler generated function 'MyApp::MyAwesomeObject ::MyAwesomeObject (const MyApp::MyAwesomeObject &)'
这个含义对我来说非常清楚,在SO中经历了很多其他问题,所有这些基本上都说“互斥不能被复制”而且我很好。所以到目前为止我的策略是将互斥量设为shared_ptr<mutex>
并完成它。唯一的“缺点”是,当我访问互斥锁时,我现在必须使用愚蠢的解除引用语法,当然这根本不是愚蠢的,只是有点尴尬,并且在我用过的所有其他点符号之间有所突出这个地方。
现在,关于我的问题:使用共享指针解决问题的正确方法是什么?可能我使用了一个独特的指针,因为据我所知,我没有将所有权转让给其他人(除非在作为对象成员的指针上调用方法实际上是一种所有权转移形式)?还有其他方法可以解决互斥锁无法复制的问题吗?
答案 0 :(得分:2)
所以到目前为止我的策略是将互斥锁设为
shared_ptr<mutex>
等待。为什么跨多种实例共享互斥锁?您是否意识到这最终会使用相同的互斥锁保护多个theList
?
你不能只把shared_ptr
放在事物上并假装它能解决问题。在这种情况下,它会改变语义。我希望这里的语义正确:每个新的MyAwesomeObject
对象都有自己的互斥锁来保护自己的theList
。
答案 1 :(得分:2)
不,使用std::shared_ptr
不是处理此问题的正确方法。
如果希望对象可以复制,则定义一个复制构造函数,用于锁定源中的互斥锁,然后复制内容。 Mike Spertus为我的博客写了一篇关于此事的客座文章:http://www.justsoftwaresolutions.co.uk/threading/thread-safe-copy-constructors.html
如果你只想要你的物体是可移动的(正如Jonathan指出的那样,只需要将它存储在矢量中),那么你可以定义一个移动构造函数,如上所述,或者遵循Jonathan的建议使用std::unique_ptr<std::mutex>
。
答案 2 :(得分:0)
不需要shared_ptr
,因为互斥锁永远不会有多个所有者。
我会使用std::unique_ptr<std::mutex>
,这会让你成为仅限移动的对象,而不是可复制的,但是可以将它们存储在vector
中。这样,您可以将列表和关联互斥锁的所有权从一个对象转移到另一个对象,但不能复制它们。
这意味着您的MyAwesomeObject
将具有空的“移动”状态,其中没有互斥锁,因此不应使用其列表。您应该添加一个成员来查询它是否处于该状态,这样用户就可以判断他们是否在没有互斥锁的情况下被赋予空对象:
class MyAwesomeObject {
std::unique_ptr<std::mutex> theListMutex;
std::list<int> theList;
public:
bool valid() const { return (bool)theListMutex; }
};
答案 3 :(得分:0)
Mutex策略应该基于“交易范围”概念而不是每个对象/或者这个。那个。
现在交易范围可以是
答案 4 :(得分:0)
另一种可能性是使用deque
或list
而不是vector
,因为它不会对其存储的类型强加可移动/可复制的要求(假设您使用{{ 1}}方法构造将元素存储在容器中,当然你没有复制容器。