不确定这是一个风格问题还是有硬性规定的事情...
如果我想尽可能地保持公共方法接口的const,但是又想使对象线程安全,那么我应该使用可变的互斥量吗?总的来说,这是好的编程风格,还是应该优先考虑非const的方法接口?请阐述你的观点。
Mutex mutex ;
int foo(const Object & object)
{
Lock<Mutex> lock(mutex) ;
return object.read() ;
}
在我看来,这是一个不好的解决方案,因为任何人都可以重用互斥锁来保护其他内容,包括你自己。实际上,如果你的代码足够复杂,你会对这个或那个互斥锁到底保护了什么感到困惑。
我知道:我曾经受到过这个问题的影响。
出于封装的目的,你应该尽可能地将互斥锁放在它所保护的对象附近。
通常,你会写一个带有互斥锁的类。但是,迟早你会需要保护一些复杂的STL结构,或者其他没有互斥锁的东西(这是一件好事)。
一个很好的方法是使用继承模板派生原始对象并添加互斥锁功能:
template <typename T>
class Mutexed : public T
{
public :
Mutexed() : T() {}
// etc.
void lock() { this->m_mutex.lock() ; }
void unlock() { this->m_mutex.unlock() ; } ;
private :
Mutex m_mutex ;
}
int foo(const Mutexed<Object> & object)
{
Lock<Mutexed<Object> > lock(object) ;
return object.read() ;
}
template <typename T>
class Mutexed : public T
{
public :
Mutexed() : T() {}
// etc.
void lock() const { this->m_mutex.lock() ; }
void unlock() const { this->m_mutex.unlock() ; } ;
private :
mutable Mutex m_mutex ;
}
我个人认为,内部互斥锁的解决方案是很好的:在一手中声明两个对象并将它们聚合在另一手中,在最终结果上是相同的。
但是聚合有以下优点:
因此,尽可能靠近互斥对象(例如使用上面的Mutexed构造)并使用mutable
限定符进行互斥锁。
显然,Herb Sutter持有相同的观点:他关于C++11中const
和mutable
的“新”含义的演示非常启发人:
http://herbsutter.com/2013/01/01/video-you-dont-know-const-and-mutable/
[回答已编辑]
基本上,在可变互斥量中使用const方法是一个好主意(顺便说一下,不要返回引用,确保通过值返回),至少可以表示它们不会修改对象。互斥锁不应该是const,将lock / unlock方法定义为const是一种无耻的谎言......
实际上,这(以及备忘录模式)是我所看到的唯一合理使用mutable
关键字的情况。
您也可以使用一个外部的互斥锁:安排所有方法都是可重入的,并让用户自己管理锁:{ lock locker(the_mutex); obj.foo(); }
并不难打,而且......
{
lock locker(the_mutex);
obj.foo();
obj.bar(42);
...
}
相比于需要两个互斥锁的方法,它具有优势(并且您可以保证对象的状态未更改)。
lock<mutex> locker(the_mutex)
吗?(而且有不提供mutex
模板参数的方法。) - sbimutable
还有其他合理的用法。缓存非平凡获取结果是一个巨大的领域,其中使用mutable
是合理的。 - VoidStar
struct process { bool started() const; void start(); };
既没有setter也没有getter,只有方法。相反,struct employee { int get_salary() const; void set_salary(int); };
让我恶心。 - Alexandre C.