C++ 'mutable' 关键字除了允许变量被 const 函数修改之外还有其他用途吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/105014/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:52:52  来源:igfitidea点击:

Does the 'mutable' keyword have any purpose other than allowing the variable to be modified by a const function?

c++keywordmutable

提问by Rob

A while ago I came across some code that marked a member variable of a class with the mutablekeyword. As far as I can see it simply allows you to modify a variable in a constmethod:

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

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

Is this the only use of this keyword or is there more to it than meets the eye? I have since used this technique in a class, marking a boost::mutexas mutable allowing constfunctions to lock it for thread-safety reasons, but, to be honest, it feels like a bit of a hack.

这是 this 关键字的唯一用途还是它的用途超出了人们的想象?从那以后,我在一个类中使用了这种技术,将 a 标记boost::mutex为可变的,允许const函数出于线程安全原因锁定它,但是,说实话,感觉有点像黑客。

采纳答案by KeithB

It allows the differentiation of bitwise const and logical const. Logical const is when an object doesn't change in a way that is visible through the public interface, like your locking example. Another example would be a class that computes a value the first time it is requested, and caches the result.

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

Since c++11 mutablecan be used on a lambda to denote that things captured by value are modifiable (they aren't by default):

由于mutable可以在 lambda 上使用c++11来表示由值捕获的事物是可修改的(默认情况下它们不是):

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

回答by Dan L

The mutablekeyword is a way to pierce the constveil you drape over your objects. If you have a const reference or pointer to an object, you cannot modify that object in any way exceptwhen and how it is marked mutable.

mutable关键字是刺破的方式const,你悬垂在你的对象面纱。如果您有一个 const 引用或指向某个对象的指针,则您不能以任何方式修改该对象,除非它何时以及如何标记mutable

With your constreference or pointer you are constrained to:

使用您的const参考或指针,您被限制为:

  • only read access for any visible data members
  • permission to call only methods that are marked as const.
  • 仅对任何可见数据成员进行读取访问
  • 仅调用标记为 的方法的权限const

The mutableexception makes it so you can now write or set data members that are marked mutable. That's the only externally visible difference.

mutable例外使得它,所以你现在可以编写或者被标记的数据集成员mutable。这是唯一的外部可见差异。

Internally those constmethods that are visible to you can also write to data members that are marked mutable. Essentially the const veil is pierced comprehensively. It is completely up to the API designer to ensure that mutabledoesn't destroy the constconcept and is only used in useful special cases. The mutablekeyword helps because it clearly marks data members that are subject to these special cases.

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

In practice you can use constobsessively throughout your codebase (you essentially want to "infect" your codebase with the const"disease"). In this world pointers and references are constwith very few exceptions, yielding code that is easier to reason about and understand. For a interesting digression look up "referential transparency".

在实践中,您可以const在整个代码库中过度使用(您本质上是想用const“疾病” “感染”您的代码库)。在这个世界中,指针和引用const很少有例外,产生的代码更容易推理和理解。对于一个有趣的题外话,请查找“参考透明度”。

Without the mutablekeyword you will eventually be forced to use const_castto handle the various useful special cases it allows (caching, ref counting, debug data, etc.). Unfortunately const_castis significantly more destructive than mutablebecause it forces the API clientto destroy the constprotection of the objects (s)he is using. Additionally it causes widespread constdestruction: const_casting a const pointer or reference allows unfettered write and method calling access to visible members. In contrast mutablerequires the API designer to exercise fine grained control over the constexceptions, and usually these exceptions are hidden in constmethods operating on private data.

如果没有mutable关键字,您最终将被迫使用它const_cast来处理它允许的各种有用的特殊情况(缓存、引用计数、调试数据等)。不幸的const_castmutable,它比强制 API客户端破坏const他正在使用的对象的保护更具破坏性。此外,它会导致广泛的const破坏:const_cast使用 const 指针或引用允许不受限制的写入和方法调用访问可见成员。相比之下,mutable需要 API 设计人员对const异常进行细粒度控制,通常这些异常隐藏在const操作私有数据的方法中。

(N.B. I refer to to data and method visibilitya few times. I'm talking about members marked as public vs. private or protected which is a totally different type of object protection discussed here.)

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

回答by Frank Szczerba

Your use with boost::mutex is exactly what this keyword is intended for. Another use is for internal result caching to speed access.

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

Basically, 'mutable' applies to any class attribute that does not affect the externally visible state of the object.

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

In the sample code in your question, mutable might be inappropriate if the value of done_ affects external state, it depends on what is in the ...; part.

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

回答by John Millikin

Mutable is for marking specific attribute as modifiable from within constmethods. That is its only purpose. Think carefully before using it, because your code will probably be cleaner and more readable if you change the design rather than use mutable.

Mutable 用于将特定属性标记为可从const方法内部修改。这是它唯一的目的。在使用它之前仔细考虑,因为如果您更改设计而不是使用mutable.

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

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

So if the above madness isn't what mutable is for, what is it for? Here's the subtle case: mutable is for the case where an object is logically constant, but in practice needs to change. These cases are few and far between, but they exist.

因此,如果上述疯狂不是 mutable 的目的,那么它是为了什么?这是一个微妙的情况:mutable 用于对象在逻辑上是恒定的,但在实践中需要改变的情况。这些案例少之又少,但它们确实存在。

Examples the author gives include caching and temporary debugging variables.

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

回答by Adam Rosenfield

It's useful in situations where you have hidden internal state such as a cache. For example:

它在您隐藏内部状态(例如缓存)的情况下很有用。例如:

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;
};

And then you can have a const HashTableobject still use its lookup()method, which modifies the internal cache.

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

回答by Lloyd

mutabledoes exist as you infer to allow one to modify data in an otherwise constant function.

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

The intent is that you might have a function that "does nothing" to the internal state of the object, and so you mark the function const, but you might really need to modify some of the objects state in ways that don't affect its correct functionality.

目的是您可能有一个对对象的内部状态“不做任何事情”的函数const,因此您标记了该函数,但您可能确实需要以不影响其正确性的方式修改某些对象状态功能。

The keyword may act as a hint to the compiler -- a theoretical compiler could place a constant object (such as a global) in memory that was marked read-only. The presence of mutablehints that this should not be done.

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

Here are some valid reasons to declare and use mutable data:

以下是声明和使用可变数据的一些正当理由:

  • Thread safety. Declaring a mutable boost::mutexis perfectly reasonable.
  • Statistics. Counting the number of calls to a function, given some or all of its arguments.
  • Memoization. Computing some expensive answer, and then storing it for future reference rather than recomputing it again.
  • 线程安全。声明 amutable boost::mutex是完全合理的。
  • 统计数据。给定函数的部分或全部参数,计算对函数的调用次数。
  • 记忆。计算一些昂贵的答案,然后将其存储以备将来参考,而不是再次重新计算。

回答by Shog9

Well, yeah, that's what it does. I use it for members that are modified by methods that do not logicallychange the state of a class - for instance, to speed up lookups by implementing a cache:

嗯,是的,这就是它的作用。我将它用于由不会在逻辑上更改类状态的方法修改的成员- 例如,通过实现缓存来加速查找:

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;
};

Now, you must use this with care - concurrency issues are a big concern, as a caller might assume that they are thread safe if only using constmethods. And of course, modifying mutabledata shouldn't change the behavior of the object in any significant fashion, something that could be violated by the example i gave if, for instance, it was expected that changes written to disk would be immediately visible to the app.

现在,您必须小心使用它 - 并发问题是一个大问题,因为如果只使用const方法,调用者可能会认为它们是线程安全的。当然,修改mutable数据不应该以任何显着的方式改变对象的行为,这可能会被我给出的例子所违反,例如,如果预期写入磁盘的更改将立即对应用程序可见.

回答by mkschreder

Mutable is used when you have a variable inside the class that is only used within that class to signal things like for example a mutex or a lock. This variable does not change the behaviour of the class, but is necessary in order to implement thread safety of the class itself. Thus if without "mutable", you would not be able to have "const" functions because this variable will need to be changed in all functions that are available to the outside world. Therefore, mutable was introduced in order to make a member variable writable even by a const function.

当您在类中有一个仅在该类中使用的变量来发出诸如互斥锁或锁之类的信号时,将使用 Mutable。这个变量不会改变类的行为,但是为了实现类本身的线程安全是必要的。因此,如果没有“mutable”,您将无法拥有“const”函数,因为在外部世界可用的所有函数中都需要更改此变量。因此,引入 mutable 是为了使成员变量即使是 const 函数也可写。

The mutable specified informs both the compiler and the reader that it is safe and expected that a member variable may be modified within a const member function.

指定的 mutable 通知编译器和阅读器,在 const 成员函数中可以修改成员变量是安全的并且是预期的。

回答by JohnMcG

Your use of it isn't a hack, though like many things in C++, mutable canbe hack for a lazy programmer who doesn't want to go all the way back and mark something that shouldn't be const as non-const.

您对它的使用不是黑客,尽管就像 C++ 中的许多东西一样,对于不想一直回去并将不应为 const 的东西标记为非常量的懒惰程序员来说,mutable可以是 hack。

回答by Greg Rogers

mutable is mainly used on an implementation detail of the class. The user of the class doesn't need to know about it, therefore method's he thinks "should" be const can be. Your example of having a mutex be mutable is a good canonical example.

mutable 主要用于类的实现细节。类的用户不需要知道它,因此他认为“应该”是 const 的方法可以是。您让互斥体可变的示例是一个很好的规范示例。