我正在维护一个包含Mutex类的库。我无法确定此类公开的lock()和unlock()函数是否应该是const。我在Web上寻找类似的代码,并且可以找到两种实现方式。
第一个实现,lock()和unlock()不是const。这意味着在const函数中使用Mutex类的人应该付出额外的努力来调用Mutex的函数:
class Mutex
{
public:
void lock();
void unlock();
};
class Foo
{
public:
void getBar(Bar& bar) const
{
m_mutex.lock();
bar = m_bar;
m_mutex.unlock();
}
private:
// Mutable, responsability of the user (or we could use a const_cast when needed)
mutable Mutex m_mutex;
Bar m_bar;
};
第二个实现,lock()和unlock()是const,即使这听起来不太自然(因为我们修改了Mutex实例),但用户在他的一个const中调用这些函数时不必费心功能:
class Mutex
{
public:
void lock() const;
void unlock() const;
};
class Foo
{
public:
void getBar(Bar& bar) const
{
m_mutex.lock();
bar = m_bar;
m_mutex.unlock();
}
private:
Mutex m_mutex;
Bar m_bar;
};
您更喜欢什么样的解决方案?我希望你的意见能帮助我做出决定。
答案 0 :(得分:10)
mutable
是为这种东西而制作的。即,mutable
适用于不参与对象的逻辑const 的事物。 (如果一个值是“逻辑常数”,则表示“主要”值是常量;对象的值从外部不能改变。)
您的对象的值是互斥锁状态的独立(它只是一个提供一致性的实现细节,并且它的状态在类外是未知的),这是一个好兆头互斥量应为mutable
。
请注意,您不应该使用const_cast
路线。 This leads to undefined behavior如果您这样做:
const Foo f;
Bar b;
f.getBar(b); // takes const off of mutex, modifies (bang you're dead)
答案 1 :(得分:8)
我更喜欢在客户端代码中生成Mutex
mutable
的第一个选项。这样,该类的用户明确地知道他正在从他的const函数调用非const函数。实际上,如果您看到CMutex类的MFC实现,则可以看到Lock
和Unlock
方法是非常量的。
答案 2 :(得分:3)
第一个实现是首选的:const条件是指逻辑const
因此,应在客户端代码中将互斥锁设为mutable
。
如果你在代码中缓存一些代价高昂的操作结果,就会出现同样的情况:你将chache变量声明为可变的,所以在计算它时你不需要抛弃类的const
- 这个
答案 3 :(得分:0)
如果你想从Mutex类派生类,那么使(两些)函数成为常量是有意义的,那么你可以在派生类自己的const函数中调用它。
像这样:
class Foo : public Mutex {
public:
void
bar() const { lock(); doSomething(); unlock(); }
}