不久前,我遇到了一些代码,它们用mutable关键字标记了一个类的成员变量。据我所知,它只是允许你在const方法中修改变量:
class Foo
{
private:
mutable bool done_;
public:
void doSomething() const { ...; done_ = true; }
};
这是唯一的使用这个关键字还是有更多的它比满足眼睛?从那以后,我在一个类中使用了这种技术,将boost::mutex标记为mutable,允许const函数出于线程安全的原因锁定它,但是,说实话,这感觉有点hack。
Mutable将const的含义从按位的const更改为类的逻辑const。
这意味着具有可变成员的类将不再是按位的const,并且将不再出现在可执行文件的只读部分中。
此外,它通过允许const成员函数在不使用const_cast的情况下更改可变成员来修改类型检查。
class Logical {
mutable int var;
public:
Logical(): var(0) {}
void set(int x) const { var = x; }
};
class Bitwise {
int var;
public:
Bitwise(): var(0) {}
void set(int x) const {
const_cast<Bitwise*>(this)->var = x;
}
};
const Logical logical; // Not put in read-only.
const Bitwise bitwise; // Likely put in read-only.
int main(void)
{
logical.set(5); // Well defined.
bitwise.set(5); // Undefined.
}
请参阅其他答案了解更多细节,但我想强调的是,这不仅仅是为了类型安全,而且它会影响编译结果。
Mutable将const的含义从按位的const更改为类的逻辑const。
这意味着具有可变成员的类将不再是按位的const,并且将不再出现在可执行文件的只读部分中。
此外,它通过允许const成员函数在不使用const_cast的情况下更改可变成员来修改类型检查。
class Logical {
mutable int var;
public:
Logical(): var(0) {}
void set(int x) const { var = x; }
};
class Bitwise {
int var;
public:
Bitwise(): var(0) {}
void set(int x) const {
const_cast<Bitwise*>(this)->var = x;
}
};
const Logical logical; // Not put in read-only.
const Bitwise bitwise; // Likely put in read-only.
int main(void)
{
logical.set(5); // Well defined.
bitwise.set(5); // Undefined.
}
请参阅其他答案了解更多细节,但我想强调的是,这不仅仅是为了类型安全,而且它会影响编译结果。
是的,这就是它的作用。我将它用于那些被方法修改的成员,而这些方法在逻辑上不会改变类的状态——例如,通过实现缓存来加速查找:
class CIniWrapper
{
public:
CIniWrapper(LPCTSTR szIniFile);
// non-const: logically modifies the state of the object
void SetValue(LPCTSTR szName, LPCTSTR szValue);
// const: does not logically change the object
LPCTSTR GetValue(LPCTSTR szName, LPCTSTR szDefaultValue) const;
// ...
private:
// cache, avoids going to disk when a named value is retrieved multiple times
// does not logically change the public interface, so declared mutable
// so that it can be used by the const GetValue() method
mutable std::map<string, string> m_mapNameToValue;
};
现在,你必须小心使用它——并发性问题是一个大问题,因为如果只使用const方法,调用者可能会认为它们是线程安全的。当然,修改可变数据不应该以任何重要的方式改变对象的行为,我给出的例子可能违反了这一点,例如,如果期望写入磁盘的更改将立即对应用程序可见。
对于那些对用户来说是逻辑上无状态的东西(因此在公共类的api中应该有“const”getter),但在底层实现(你的.cpp中的代码)中不是无状态的东西,使用“mutable”。
The cases I use it most frequently are lazy initialization of state-less "plain old data" members. Namely, it is ideal in the narrow cases when such members are expensive to either build (processor) or carry around (memory) and many users of the object will never ask for them. In that situation you want lazy construction on the back end for performance, since 90% of the objects built will never need to build them at all, yet you still need to present the correct stateless API for public consumption.