不久前,我遇到了一些代码,它们用mutable关键字标记了一个类的成员变量。据我所知,它只是允许你在const方法中修改变量:

class Foo  
{  
private:  
    mutable bool done_;  
public:  
    void doSomething() const { ...; done_ = true; }  
};

这是唯一的使用这个关键字还是有更多的它比满足眼睛?从那以后,我在一个类中使用了这种技术,将boost::mutex标记为mutable,允许const函数出于线程安全的原因锁定它,但是,说实话,这感觉有点hack。


当前回答

mutmutable确实存在,因为你可以推断允许在一个常量函数中修改数据。

这样做的目的是,您可能有一个函数对对象的内部状态“什么都不做”,因此您将函数标记为const,但您可能确实需要以不影响其正确功能的方式修改一些对象的状态。

关键字可以作为对编译器的提示——理论上的编译器可以将一个常量对象(例如全局变量)放在内存中,并将其标记为只读。可变的存在提示不应该这样做。

下面是声明和使用可变数据的一些有效理由:

线程安全。声明一个可变的boost::mutex是完全合理的。 统计数据。给定函数的部分或全部实参,计算函数的调用次数。 记忆。计算一些代价高昂的答案,然后将其存储起来以备将来参考,而不是重新计算。

其他回答

在为类测试目的创建存根时,mutable关键字非常有用。你可以存根一个const函数,仍然能够增加(可变的)计数器或任何你已经添加到存根的测试功能。这使存根类的接口保持不变。

使用boost::mutex正是这个关键字的目的。另一个用途是内部结果缓存,以加快访问速度。

基本上,'mutable'适用于任何不影响对象外部可见状态的类属性。

在你的问题中的示例代码中,mutable可能是不合适的,如果done_的值影响外部状态,它取决于…;部分。

它允许区分按位的const和逻辑的const。逻辑const是指对象没有以通过公共接口可见的方式更改,就像锁定示例一样。另一个例子是一个类,它在第一次请求时计算一个值,并缓存结果。

因为c++11 mutable可以用在lambda上,表示用value捕获的东西是可修改的(默认情况下不是):

int x = 0;
auto f1 = [=]() mutable {x = 42;};  // OK
auto f2 = [=]()         {x = 42;};  // Error: a by-value capture cannot be modified in a non-mutable lambda

经典的例子(在其他回答中提到),也是我迄今为止看到的使用mutable关键字的唯一情况,是用于缓存复杂的Get方法的结果,其中缓存是作为类的数据成员实现的,而不是作为方法中的静态变量(出于几个函数之间共享或简单清洁的原因)。

一般来说,使用mutable关键字的替代方法通常是方法中的静态变量或const_cast技巧。

另一个详细的解释在这里。

mutable关键字是一种戳穿对象上的const面纱的方法。如果你有一个指向对象的const引用或指针,你不能以任何方式修改该对象,除非它被标记为可变的。

使用const引用或指针,你被限制为:

仅对任何可见数据成员进行读访问 只调用标记为const的方法的权限。

可变异常使您现在可以编写或设置标记为可变的数据成员。这是唯一能从外部看到的区别。

在内部,那些对你可见的const方法也可以写入标记为可变的数据成员。本质上,const面纱是全面穿透的。完全由API设计者来确保mutable不会破坏const概念,并且只在有用的特殊情况下使用。mutable关键字有帮助,因为它清楚地标记了受这些特殊情况影响的数据成员。

在实践中,您可以在整个代码库中频繁地使用const(实际上您希望用const“疾病”“感染”代码库)。在这个世界中,指针和引用都是const的,只有极少数例外,从而产生的代码更容易推理和理解。一个有趣的题外话,请查阅“参考透明度”。

Without the mutable keyword you will eventually be forced to use const_cast to handle the various useful special cases it allows (caching, ref counting, debug data, etc.). Unfortunately const_cast is significantly more destructive than mutable because it forces the API client to destroy the const protection of the objects (s)he is using. Additionally it causes widespread const destruction: const_casting a const pointer or reference allows unfettered write and method calling access to visible members. In contrast mutable requires the API designer to exercise fine grained control over the const exceptions, and usually these exceptions are hidden in const methods operating on private data.

(注意:我多次提到数据和方法可见性。我说的是标记为public、private或protected的成员,这是这里讨论的完全不同类型的对象保护。)