c - 'mutable'关键字是否有用途, 而不是允许修改的变量声明为const函数?

  显示原文与译文双语对照的内容

随着 mutable keyword,不久前里我找到的一些代码,这些代码标记为一个成员变量,一个职业。 在一个 const method,就现在能看到它只允许你修改一个 variable:


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

这是唯一使用这里关键字或者这儿没有别的房间的比看起来的那么简单? 我有一个类,打标 boost::mutex 作为可变允许 const 函数按照中因为使用这种技术针对thread-safety锁定原因,但是,老实说,这感觉象有点外挂。

时间:

它允许按位构造和逻辑构造。 逻辑const是当对象没有通过公共接口可见的方式更改时,如你的锁定示例。 另一个示例是在第一次请求值时计算值的类,并缓存结果。

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


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 关键字是一种刺穿你在对象上折叠的const 头纱的方法。 如果你有一个常量引用或者指针,该指针指向对象,就不能修改该对象以任何方式以及它如何被标记 mutable 时 除外。

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

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

mutable 异常使你可以编写或者设置标记为 mutable的数据成员。 这是唯一一个外部可见的差异。

内部可见的const 方法也可以写入标记为 mutable的数据成员。 基本上,const veil是comprehensively的。 它完全取决于API设计器,确保 mutable 不会破坏 const 概念,并且只用于有用的特殊情况。 mutable 关键字有帮助,因为它清楚地标记了那些受这些特殊情况影响的数据成员。

实际上你可以使用 const 痴迷你整个代码库( 你基本上想"感染"带 const的代码库"疾病") 在这个世界中指针和引用是 const,很少例外,产生更容易理解和理解的代码。 对于一个有趣的digression查找"引用透明度"。

没有 mutable 关键字,你最终将不得不使用 const_cast 来处理它所允许的各种有用的特殊情况。 使用,遗憾的是比 mutableconst_cast 是明显更具有破坏性,因为它将迫使 API 客户端毁了那( s ) const 保护的对象对于非门 此外,它还导致了广泛的const 破坏: const_cast 指定常量指针或者引用允许不受限制的写入和方法调用对可见成员的访问。 相反,mutable 要求API设计器对 const 异常进行精细的粒度控制,通常这些异常在私有数据操作的const 方法中隐藏。

( 注意。我是指为了给资料,方法可见性几次。 我讨论标记为公共 vs 私有或者保护的成员,这是一个完全不同的对象保护类型,这里讨论的是 。)

可以变量用于将特定属性标记为在 const 方法中可以修改。 这是唯一的目的。 在使用之前仔细考虑,因为如果你更改设计而不是使用 mutable,代码可能会更清晰更易读。

http://www.highprogrammer.com/alan/rants/mutable.html

所以如果上面的疯狂不是可变的,它是什么? 下面是一个微妙的例子:可变的是一个对象在逻辑上是恒定的,但在实践中需要改变。 这些案例很少,但它们存在。

作者提供的示例包括缓存和临时调试变量。

它在隐藏内部状态( 如缓存) 时很有用。 例如:

class HashTable
{
...
public:
 string lookup(string key) const
 {
 if(key == lastKey)
 return lastValue;
 string value = lookupInternal(key);
 lastKey = key;
 lastValue = value;
 return value;
 }
private:
 mutable string lastKey, lastValue;
};

然后,const HashTable 对象仍然使用它的lookup() 方法,它修改内部缓存。

是的,是这样的。 我使用这个词这是为会员受方法若不逻辑上改变它的状态的类- 例如为了加速查找通过实现一个缓存:


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 方法。 当然,修改 mutable 数据不应该改变对象的行为,例如我给出的例子可能会被示例所认为的更改立即可见。

当推断为允许在其他常量函数中修改数据时,mutable 确实存在。

在不影响它的正确functionality,的方式这样做的目的是,你可能有一个函数,该函数对对象的内部状态,以便你将函数标记 const"不执行任何操作"子来的对象,但是你可能确实需要修改一些,

在内存中已经标记关键字可能会像一个提示编译器--全文分析的理论,编译器可以放置一个常量对象 mutable 提示表明不应该这样做。

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

  • 线程安全。声明 mutable boost::mutex 是完全合理的。
  • 统计。计算函数的调用次数,给定部分或者全部参数。
  • 记忆。计算一些昂贵的答案,然后保存以备将来参考,而不是重新计算。
...