Does the 'mutable' keyword have any purpose other than allowing a data member to be modified by a const member function?
Asked Answered
M

18

634

A while ago, I came across some code that marked a data member of a class with the mutable keyword. As far as I can see it simply allows you to modify a member in a const-qualified member method:

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::mutex as mutable, allowing const functions to lock it for thread-safety reasons, but, to be honest, it feels like a bit of a hack.

Morion answered 19/9, 2008 at 19:58 Comment(5)
A question though, if you are not modifying anything, why do u need to use a mutex in first place? I just want to understand this.Cucumber
@Cucumber you are modifying something, you just are controlling who/how can do the modification via const. A really naive example, imagine if I only give non-const handles to friends, enemies get a const handle. Friends can modify, enemies cannot.Nieberg
Note: here's a great example of using the keyword mutable: #15999623Wynn
I wish it could be used to override const (of types) so I don't have to do this: class A_mutable{}; using A = A_mutable const; mutable_t<A> a;, if I want const-by-default, i.e. mutable A a; (explicit mutable) and A a; (implicit const).Faggot
@Cucumber because other threads are modifying.Alexipharmic
T
438

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 mutable can be used on a lambda to denote that things captured by value are modifiable (they aren't by default):

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
Thetes answered 19/9, 2008 at 20:4 Comment(15)
'mutable' does not affect bitwise/logical constness at all. C++ is only bitwise const and the 'mutable' keyword can be used to exclude members from this checking. It is not possible to achieve 'logical' const in C++ other than via abstractions (eg. SmartPtrs).Provide
@Richard: you're missing the point. There is no "logical const" keyword, true, rather, it's a conceptual differentiation the programmer makes to decide which members should be excluded by being made mutable, based on an understanding of what constitutes the logical observable state of the object.Intersperse
I think @Richard's comment is valuable in that it helps clarify KeithB's explanation with some more detail. At least it helped me :)Juanajuanita
Both KeithB and @RichardCorden are correct, depending on perspective. Were the terms used by KeithB more rigorously defined, there would be no ambiguity (and probably no disagreement); but the ambiguity does not interfere with the value of KeithB's answer, in my opinion - it's a valuable answer, and a correct one, I think.Crumpled
can we change mutable data members of a const object.?Bolo
@ajay Yes, that is the whole point of markig a member variable as mutable, to allow it to be changed in const objects.Thetes
Why does one need mutable on lambdas? Wouldn't it suffice to capture variable by reference?Listed
@Giorgio: The difference is that the modified x within the lambda remains within the lambda, i.e. the lambda function can only modify its own copy of x. The change is not visible outside, the original x is still unchanged. Consider that lambdas are implemented as functor classes; captured variables correspond to member variables.Emmons
@phresnel: OK, then I do not understand why captured variables (member variables that are copies of variables from the context) are const by default. Is there a particular reason for this?Listed
"Logical const is when an object doesn't change in a way that is visible through the public interface, like your locking example.": In what sense using a mutex does not change the observable behaviour of an object? The next time a locking method is invoked by another thread, the method will stop and wait until the thread holding the lock exits the locking method. This looks like an observable change of behaviour to me.Listed
@Giorgio: Maybe my new Q/A helps a bit: #16945394Emmons
@Giorgio, let's say I have a toaster and I place it in a room. When people want to use the toaster, you enter the room and lock the door. When you're done, you unlock the door and exit the room (door can only be locked/unlocked from the inside). Say I gain access to the room, lock the door, and use the toaster. You want to use the toaster. But the door is locked. Has the observable behavior of the toaster changed? No. Toaster still holds only two pieces of bread. Still converts raw bread into toast. Gaining access to the toaster isn't part of the toaster's behavior.Nieberg
@Nieberg Excellent analogy, wittily delivered. And eerily apt, since the other day, having to take a break from fruitless debugging - which would later be shown to be related to threading, no less - I thought I'd relax with some toasted potato scones (yeah, that's what I'm talking about). Instead, I blew the circuit breaker. Considering what preceded this attempt, I have no idea why I was mildly surprised! I guess my toaster wasn't thread safe either.Dover
why bother using mutable when removing const enables mutability? Isn't overriding constness a bad thing in the first place?Halfdan
@Halfdan using const keyword implies a constness from the perspective of the user of the class. If I initialise c1 and c2 as const MyCls c1(); const MyCls c2 = c1; then in any part of the code from there onwards, c1 == c2 must always be true. Since equality is defined by the class itself, it can choose which members to use for equality check. Hence (for eg.) if it decides only to use public members for this check, then it can make private variables as mutable as this does not change the constness of the object and may also help the object for its internal workings.Stolen
R
175

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

With your const reference or pointer you are constrained to:

  • only read access for any visible data members
  • permission to call only methods that are marked as const.

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

Internally those const methods 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 mutable doesn't destroy the const concept and is only used in useful special cases. The mutable keyword helps because it clearly marks data members that are subject to these special cases.

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

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.

(N.B. I refer to to data and method visibility a 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.)

Rubie answered 5/3, 2010 at 2:34 Comment(4)
Plus, using const_cast to modify a part of a const object yields undefined behaviour.Cairns
I don't agree with because it forces the API client to destroy the const protection of the objects. If you were using const_cast to implement mutation of member variables in a const method, you wouldn't ask the client to the do the cast - you'd do it within the method by const_casting this. Basically it lets you bypass constness on arbitrary members at a specific call site, while mutable let's you remove const on a specific member at all call sites. The latter is usually what you want for the typical use (caching, stats), but sometimes the const_cast fits the pattern.Butcher
The const_cast pattern does fit better in some cases, such as when you want to temporarily modify a member, then restore it (pretty much like boost::mutex). The method is logically const since the final state is the same as the initial, but you want to make that transient change. const_cast can be useful there because it lets you cast away const specifically in that method were you the mutation will be undone, but mutable wouldn't be as appropriate since it would remove const protection from all methods, which don't necessarily all follow the "do, undo" pattern.Butcher
The possible placement of const defined object into read-only memory (more generally, memory marked read-only) and the associated standard language that allows this makes const_cast a possible time-bomb though. mutable has no such issue since such objects could not be placed in read-only memory.Butcher
C
81

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

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.

Chaconne answered 19/9, 2008 at 19:58 Comment(0)
C
42

Mutable is for marking specific attribute as modifiable from within const methods. 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.

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.

Examples the author gives include caching and temporary debugging variables.

Coldhearted answered 19/9, 2008 at 20:2 Comment(3)
I think this link gives the best example of a scenario where mutable is helpful.It almost appears they are exclusively used for debugging. (per correct usage)Tachistoscope
The usage of mutable can make the code more readable and cleaner. In the following example, the read can be const as expected. ` mutable m_mutex; Container m_container; void add(Item item) { Lockguard lock(m_mutex); m_container.pushback(item); } Item read() const { Lockguard lock(m_mutex); return m_container.first(); } `Offshore
There's one extremely popular use case: ref counts.Kumasi
I
38

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 HashTable object still use its lookup() method, which modifies the internal cache.

Idioblast answered 19/9, 2008 at 20:3 Comment(1)
The example is good, but this practice hides a dangerous consequence. Someone looking to the lookup call may think that it is thread safe since it "does not" change the state of the object because of the const qualifier. Later when things don't work... hours of work is thrown away in order to find the race condition. It is a terrible practice.Lebrun
I
12

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

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.

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 mutable hints that this should not be done.

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

  • Thread safety. Declaring a mutable boost::mutex is 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.
Isaiah answered 19/9, 2008 at 20:25 Comment(4)
Good answer, except for comment regarding mutable being a "hint". This makes it seem as if the mutable member sometimes won't be mutable if the compiler placed the object into ROM. The behaviour of mutable is well defined.Provide
Apart from placing a const object in read-only memory, the compiler may also decide to optimize const fucntion calls out of a loop, for example. A mutable statistics counter in an otherwise const function will still allow such optimization (and count only one call) instead of preventing optimization just for the sake of counting more calls.Azerbaijan
@HagenvonEitzen - I'm pretty sure that is incorrect. A compiler cannot hoist functions out of a loop unless it can prove there are no side effects. That proof generally involves actually inspecting the implementation of the function (often after it is inlined) and not relying on const (and such an inspection will succeed or fail irrespective of const or mutable). Simply declaring the function const isn't enough: a const function is free to have side effects such as modifying a global variable or something passed to the function, so it isn't a useful guarantee for that proof.Butcher
Now, some compilers have special extensions such as gcc's _attribute__((const)) and __attribute__((pure)), which _do have such effects, but that's only tangentially related to the const keyword in C++.Butcher
V
12

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.

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.

Vietnamese answered 28/6, 2013 at 12:31 Comment(0)
W
10

Well, yeah, that's what it does. I use it for members that are modified by methods that do not logically change 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 const methods. And of course, modifying mutable data 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.

Wilburwilburn answered 19/9, 2008 at 20:7 Comment(0)
B
8

Use "mutable" when for things that are LOGICALLY stateless to the user (and thus should have "const" getters in the public class' APIs) but are NOT stateless in the underlying IMPLEMENTATION (the code in your .cpp).

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.

Brightwork answered 14/1, 2014 at 2:38 Comment(0)
A
7

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.

Addis answered 19/9, 2008 at 20:5 Comment(0)
C
5

Your use of it isn't a hack, though like many things in C++, mutable can be 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.

Cabretta answered 19/9, 2008 at 20:20 Comment(0)
M
5

Mutable changes the meaning of const from bitwise const to logical const for the class.

This means that classes with mutable members are longer be bitwise const and will no longer appear in read-only sections of the executable.

Furthermore, it modifies type-checking by allowing const member functions to change mutable members without using 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.
}

See the other answers for more details but I wanted to highlight that it isn't merely for type-saftey and that it affects the compiled result.

Multiplicity answered 24/7, 2014 at 19:50 Comment(0)
N
3

The mutable keyword is very useful when creating stubs for class test purposes. You can stub a const function and still be able to increase (mutable) counters or whatever test functionality you have added to your stub. This keeps the interface of the stubbed class intact.

Naivete answered 27/5, 2014 at 8:6 Comment(0)
M
2

The classic example (as mentioned in other answers) and the only situation I have seen the mutable keyword used in so far, is for caching the result of a complicated Get method, where the cache is implemented as a data member of the class and not as a static variable in the method (for reasons of sharing between several functions or plain cleanliness).

In general, the alternatives to using the mutable keyword are usually a static variable in the method or the const_cast trick.

Another detailed explanation is in here.

Metric answered 16/5, 2011 at 12:32 Comment(3)
I've never heard of using static members as a general alternative to mutable members. And const_cast is only for when you know (or have been guaranteed) that something will not be changed (e.g. when interfering with C libraries) or when you know it wasn't declared const. I.e., modifying a const-casted const variable results in undefined behaviour.Emmons
@phresnel By "static variables" I meant static automatic variables in the method (that stay across calls). And const_cast can be used to modify a class member in a const method, which is what I referred to...Metric
That was not clear to me, as you wrote "in general" :) With regards to modifying through const_cast, as said this is only allowed when the object was not declared const. E.g. const Frob f; f.something();, with void something() const { const_cast<int&>(m_foo) = 2; results in undefined behaviour.Emmons
B
2

The mutable can be handy when you are overriding a const virtual function and want to modify your child class member variable in that function. In most of the cases you would not want to alter the interface of the base class, so you have to use mutable member variable of your own.

Birdhouse answered 1/2, 2014 at 14:15 Comment(0)
N
1

In some cases (like poorly designed iterators), the class needs to keep a count or some other incidental value, that doesn't really affect the major "state" of the class. This is most often where I see mutable used. Without mutable, you'd be forced to sacrifice the entire const-ness of your design.

It feels like a hack most of the time to me as well. Useful in a very very few situations.

Noctambulism answered 19/9, 2008 at 20:3 Comment(0)
U
-1

One of the best example where we use mutable is, in deep copy. in copy constructor we send const &obj as argument. So the new object created will be of constant type. If we want to change (mostly we won't change, in rare case we may change) the members in this newly created const object we need to declare it as mutable.

mutable storage class can be used only on non static non const data member of a class. Mutable data member of a class can be modified even if it's part of an object which is declared as const.

class Test
{
public:
    Test(): x(1), y(1) {};
    mutable int x;
    int y;
};

int main()
{
    const Test object;
    object.x = 123;
    //object.y = 123;
    /* 
    * The above line if uncommented, will create compilation error.
    */   

    cout<< "X:"<< object.x << ", Y:" << object.y;
    return 0;
}

Output:-
X:123, Y:1

In the above example, we are able to change the value of member variable x though it's part of an object which is declared as const. This is because the variable x is declared as mutable. But if you try to modify the value of member variable y, compiler will throw an error.

Urdar answered 25/1, 2015 at 18:19 Comment(1)
The paragraph about copying makes no sense. The copy constructor and assignment operator can modify the destination object they are constructing or assigning. They should have no reason to modify the source object. The source object being const& has no bearing upon these facts.Dover
S
-6

The very keyword 'mutable' is actually a reserved keyword.often it is used to vary the value of constant variable.If you want to have multiple values of a constsnt,use the keyword mutable.

//Prototype 
class tag_name{
                :
                :
                mutable var_name;
                :
                :
               };   
Selectivity answered 22/2, 2014 at 3:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.