mutable and const

Started by
15 comments, last by iMalc 14 years, 10 months ago
I'm not a big fan of the 'mutable' storage class specifier. However, it seems inevitable, for example in a sort of stream base class.
Quote:

class Stream
{
    virtual bool read(void* ptr, const int len) const { m_pointer += len; return true; }
    virtual bool write(const void* ptr, const int len) { m_pointer += len; return true; }

    mutable int pointer; // needs to be mutable to push the stream pointer in the read() method.
};
Is there any clean way round it (while still maintaining the read() method to be declared 'const').

Everything is better with Metal.

Advertisement
I can only imagine 2 other ways, both of which seem more unclean than a mutable variable:

* have a pointer/reference type: but Stream then depends on "third party storage"
* use, ahem, const_cast<>, or better, don't.

Note that a function being const shall not change the classes externally visible state, not its internal one. I guess streams are pretty borderline in this respect, because two consecutive reads with the same arguments might not yield the same return value. Dunno, I would prefer mutable.

[Edited by - phresnel on June 2, 2009 9:00:40 AM]
Why is your 'read' function declared const? Just remove it and you won't need 'mutable'.
const-correctness is about the immutability of the object's state, not its individual members. An object is considered immutable even if some internally used attributes change but the object's state appears to be unchanging from an external point of view. This is perfectly fine and there's no need to work around that.
Quote:Original post by phresnel
* use, ahem, const_cast<>, or better, don't.


Why? This is what I have traditionally used in the past to get around this kind of borderline area. Would making the variable mutable be a better approach?
Quote:
const-correctness is about the immutability of the object's state, not its individual members. An object is considered immutable even if some internally used attributes change but the object's state appears to be unchanging from an external point of view. This is perfectly fine and there's no need to work around that.


right-o. I think I'll stick with it. It's one of the C++ quirks.

I prefer mutable on individual members, over type casts that discards type qualifiers, or not using a constant qualifier at all.

The 'read' function is just an example. Reading from a file, your are not modifying it (it can be read-only and still works). I suppose the analogy (probably wrong) would be a read-only file, but attributes can change (obviously, the write-protected flag needs to be modifiable).

The problem with const is that it has a domino effect. Once you use it somewhere, it is likely it will affect other function declarations.

Everything is better with Metal.

Any time you feel that some language construct does not work the way you would like is probably an indication that you're trying to do something wrong.

In this case, you've made some functions const yet they modify the state of your object. Fact is, reading and wring your stream modifies the state of your stream, so they are not candidates for being const functions. Simple as that. No need to use mutable.

If you're going to reinvent what the language provides for you you might consider benefitting from the experience and wisdom of those who designed the laguage. For example, C++ provides stream classes with read() and write() functions, and yet those functions of the standard classes are not const. Why not?

Stephen M. Webb
Professional Free Software Developer

I agree, read() isn't a const operation here. While conceptually the underlying data isn't modified, the position in the stream is.
Quote:Original post by _moagstar_
Quote:Original post by phresnel
* use, ahem, const_cast<>, or better, don't.


Why? This is what I have traditionally used in the past to get around this kind of borderline area. Would making the variable mutable be a better approach?


I think the standard allows const_cast to reference and then changing the value of the referencee if the referencee happens to be non-const (i.e. not declared with const), but I personally think that const_cast's are plain ugly, the cast will always work (uninteded harddisk formatting or not), never mind whether the casted value is really const or not. But if I don't use const_cast, but instead declare the variable to be mutable, and then someday decide it shall no longer be mutable, the compiler will direct me to the points where I try to assign to it. But with a const_cast, if I happen to make some variable really const, the compiler won't bite me, and under uncertain conditions the application may crash.

Valid code:
class X {    int x;    void f () const {        const_cast<int&> (x)++;    }};


But then, Joey finds that x'd better be const (even if he's missassuming something here):

class X {    const int x;    void f () const {        const_cast<int&> (x)++;    }};


It still compiles, hopefully with a warning diagnostic, but it may crash freely during execution. Using mutable to state that you mean "x might change even in const function" might have prevented Joey from making it x const, because somebody else explicitly stated "x might change in const functions".

So, my opinion is that using const_cast for the sake of (alleged) const correctness is wrong, because there's potentially more trouble you can get in than with mutable.
Quote:Original post by oliii
The problem with const is that it has a domino effect. Once you use it somewhere, it is likely it will affect other function declarations.


Exactly. Begin soon with const-correctness, and imho, write RAII classes, which helps a lot with const-correctness (you can often make all members const if you don't have Init() or SetScreenSize(int,int) functions, but that is also POV).

This topic is closed to new replies.

Advertisement