mutable variables and const functions

Hello everybody,
I was reading about mutable variables and I have a problem understanding their purpose.
I understand that mutable variables can be altered by const functions. But what is the reason of declaring a function as const and then some variables as mutable and not just use normal variables and non const functions?
Can you give me a practical example of that? (Not code, just explain it if you can)

Thank you.
I wish i could answer that, but I've always have had a bit of trouble understanding why or where to use const variables. I understand that const means it can't be changed, but what is the difference between

const char *mystring[];
and
char const *mystring[];

And what do i make out of a function header like
const void const myfunct (const char const *mystring[]) // way too many consts in there..
I'm currious to figgure this out as well.
The first is either a constant pointer to an array of pointers to C strings, or a pointer to an array of pointers to constant C strings. The second is a pointer to an array of constant pointers to C strings. The function is constant (whatever that means) and returns a constant void (I'm pretty sure that's illegal, BTW). It takes a constant pointer to an array of constant pointers to C strings. I'd love to see a constant pointer to that function.

This is exactly why I consider the best course of action to simply not use consts at all except in the most obvious of cases (const float pi=3.141592 and such).
And I'm not too crazy about OOP, either.
You're actually reading the *mystring[] wrong. It's not a pointer to an array of string pointers. It's a pointer to an array of characters, eg: a pointer to 1 c string.

So const char *mystring[] is a constant pointer (meaning the pointer can't be changed) to a c str (which can be changed)
and char const *mystring[] is a pointer (which can be changed) to a constant c str (which can't)
is that correct?
and then the function, a bit different this time
const int myfunction (const int const * myint)

So the returned int is constant?
If i call
int a = myfunction (10)
then a cannot be changed? it's constant?
How about the rest, the pointer to the int inside myfunction cannot be changed, nor can the value? why not just pass as refference?

It makes no sense to me. The only thing I can see where these come in handy is when making functions for other ppl to use, and forcing them to call the function correctly.
It's not a pointer to an array of string pointers. It's a pointer to an array of characters, eg: a pointer to 1 c string.

No, it's not. All [] after a symbol can be translated to a * before that symbol. So char *a[] is the same as char **a. This makes perfect sense, as char *a[] suggests an array of char *. You can test it:
1
2
3
4
5
6
7
8
9
char *a[]={
    "Adam",
    "Ben",
    "Charlie",
    "Dennis",
    0
}
for (short b=0;a[b];b++)
    std::cout <<a[b]<<std::endl;



and then the function, a bit different this time
const int myfunction (const int const * myint)

So the returned int is constant?
If i call
int a = myfunction (10)
then a cannot be changed? it's constant?
How about the rest, the pointer to the int inside myfunction cannot be changed, nor can the value? why not just pass as refference?

Oh, god. I think my brain just flipped over inside my head.
yea.. i think i'll just avoid using const keyword for now except in a few rare occasions such as your pi example. it gets very confusing.
OK...
What about the mutable now? What is a practical usage of it?
This may have what you seek: http://en.wikipedia.org/wiki/Const-correctness
But if I was you, I would stay away from these mostly useless and utterly confusing constructs.
closed account (z05DSL3A)
Mitsakos wrote:
But what is the reason of declaring a function as const and then some variables as mutable and not just use normal variables and non const functions?
Can you give me a practical example of that? (Not code, just explain it if you can)


I can't think of a good example at the moment but...

The reason for declaring a member function as const is that they are the only nonstatic member functions that can be invoked from objects declared using the keyword const.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>

class Point
{
public:
    Point()
    {
        //...
    }

    void foo()
    {
        //...
    }
    void bar() const
    {
        //...
    }

private:
    //...
};

int main()
{
    const Point origin;

    origin.foo(); // error C2662: 'Point::foo':
                  // cannot convert 'this' pointer from 'const Point' to 'Point &'	

    origin.bar(); //OK

    return 0;
}


If part of the class state needs to be changed for the function bar() to do its magic, then the relevant data members need to be marked as mutable to allow them to be change if the object in const.

HTH
To helios: no offense, but what kind of advice is "stay away from these mostly useless and utterly confusing constructs" on a C++ forum? IMHO it is very important to learn how to write const-correct code. The Wiki page is useful. When I was learning how to "parse" declarations with consts all over the place, I took some notes, which I've attached here:

This file explains how const works.

The following declarations are identical:
const char* p;
char const* p;

Both declare a pointer to a constant character. The second is slightly
better in the sense that the declaration can be read from right-to-left:
"p is a pointer to a const char". Read as such, it is easy to see that
the line *p = 'c'; will not compile.

The following declaration:
char* const p;

declares p to be a constant pointer to a character. That is:
p = "foo"; // Does not compile
*p = 'f'; // Compiles!

And thus:
const char* const p;
char const* const p;

both declare p to be a constant pointer to a constant character, and
so none of the following lines of code compile:
p = "foo";
*p = 'f';


Now throw another pointer into the mix:
const char** p;
char const** p;

These are equivalent and declare p to be a pointer to a pointer to a
constant character. That is:
p = ptr-to-ptr-to-char; // Compiles
*p = ptr-to-char; // Compiles
**p = 'f'; // Does not compile

Or how about creative placement of const:
char* const* p;

This declares p to be a pointer to a constant pointer to a character.
That is:
p = ptr-to-constptr-to-char; // Compiles
*p = ptr-to-char; // Does not compile
*p = constptr-to-char; // Does not compile
**p = 'f'; // Compiles

And the ever-popular:
char** const p;

Which declares p to be a constant pointer to a pointer to a character.
Or:
p = ptr-to-ptr-to-char; // Does not compile
p = constptr-to-ptr-to-char; // Does not compile
*p = ptr-to-char; // Compiles
**p = 'f'; // Compiles

And now we get just plain const happy:
const char* const* p;

p is a pointer to a constant pointer to a constant character. The only
thing you can do with this one (besides remove the code and rewrite) is:
p = ptr-to-constptr-to-constchar;

const char** const p;
p is a constant pointer to a pointer to a constant character. The only
thing you can do with this is:
*p = ptr-to-constchar;

And this beast:
const char* const* const p;

Well, it won't pass code review since nobody will understand it, but at
any rate... We've achieved maximum constant-ness with this line. You
can't do anything at all with p, what it points to, what that points to,
or what "what that" points to. You can print it. That's about it.


Ho-ho, and the fun is just beginning. Now throw in REFERENCES!

const char& p;
char const& p;

These both declare p to be a reference to a constant character. That is,
p cannot change.

char& const p;
const char& const p;
char const& const p;
char*& const p;
const char*& const p;
const char* const& const p;

These all generate compiler errors, because there is no such thing as
a constant reference I guess.

const char*& p;
char const*& p;

p is a reference to a pointer to a constant character. One can change p,
but not *p.

char* const& p;

p is a reference to a constant pointer to a character.

const char* const& p;

p is a reference to a constant pointer to a constant character.

const char&* p;
char const&* p;
char& const* p;
char&* const p;
const char& const* p;
const char&* const p;
const char& const* const p;

Fortunately pointers to references are not allowed. The above declarations
are illegal. The programmer who attempts to use the above declarations
should be fired anyway.


As for mutable and const member functions.
Here's an example:

1
2
3
4
5
6
7
8
class Foo {
  public:
      void DoSomething() const;
  private:
      int someData;
      char moreData;
      float yetMoreData;
};


Note the "const" after DoSomething(). This means that DoSomething() is a const member function. This says that DoSomething() will not modify any of its own data members when it executes. Why is saying this useful? Because it is a contract to Foo's user. Let's extend the example:

1
2
3
4
5
6
7
8
9
10
11
12
class Foo {
  public:
      void DoSomething() const;
      void WorkHard();
      void PrintMe() const
        { cout << someData << ", " << moreData << ", " << yetMoreData << endl; }

  private:
      int someData;
      char moreData;
      float yetMoreData;
};


(I've omitted things like constructors, etc, to distill the code to its bare essence)
Suppose you have a variable of type Foo, and that Foo's data members were
actually initialized to something useful:

1
2
3
4
5
Foo f;   // Let's say someData = 42, moreData = 'X', and yetMoreData = 3.14.

f.PrintMe();  // Prints 42, X, 3.14
f.DoSomething();
f.PrintMe();  // Better print 42, X, and 3.14 


Why do I say that the second call to PrintMe() better print the same values as
the first call? How can I even know as a user of Foo, since I can't see what
DoSomething() does? Because DoSomething() is a const member function. It is
a contract to me, the user, that says that DoSomething() will not modify any of its
(non-mutable, but more on that later) data members.

Now notice that WorkHard() is not declared as a const member function. So:

1
2
3
4
5
Foo f;   // Let's say someData = 42, moreData = 'X', and yetMoreData = 3.14.

f.PrintMe();  // Prints 42, X, 3.14
f.WorkHard();
f.PrintMe();  // What will this print? 


Because WorkHard() is not declared const, it means that WorkHard() might modify one or more of the data members. Hopefully the description of the function tells me exactly what it does. For example "multiplies someData by 2, increments moreData and wraps
at 'Z' back to 'A'. Does not modify yetMoreData." Unfortuantely, in practice, too many developers don't document well and don't follow const-correctness, and all too often it actually becomes hard to know whether a member function will modify state or not without looking at the implementation of the function (sometimes it is not obvious).

The point is... declaring a member function const is part of the API that you are giving to the programmer who will use your code.

Now, on to mutable. First, a classroom example, and then I'll give you a real-world example of where I used mutable in my code (I cannot publish the code here, but I will explain why I needed/wanted to use mutable).

So const is part of the API of the class to the programmer, to guarantee that the object won't "change state" across calls to the function. Sometimes, your object might have some very internal data that your user couldn't possibly care about. For example, let's say you have a class that can send messages on a socket.

1
2
3
4
5
6
7
class MySocket {
   public:
      // ...
      int Send( const char* data, int length ) const;
   private:
      int sock;       // The file descriptor used to send data
};


I declared Send() to be const, because it doesn't change any data members (sock).

Now, suppose for whatever reason I, the programmer of Socket, want to copy the
user's data into an internal cache in the class. Let's also say that my user cannot possibly care about what is in the internal cache.

1
2
3
4
5
6
7
8
class MySocket {
   public:
      // ...
      int Send( const char* data, int length ) const;
   private:
      int sock;       // The file descriptor used to send data
      mutable char cache[ 4096 ];   // Ok, yes, hard-coded constant is hideous.  anyway.      
};


So now Send() wants to copy the user's data into the cache, but it can't because
Send() is a const member function. So I make my cache mutable, and now Send()
can do this.

Why, you ask, don't I just make Send() non-const and forget the mutable? Possibly two reasons. First, if there is a lot of code using Socket already, it might be impractical for me to change Send() this way without causing a lot of compile errors (because my users might have been relying on Send() being const when they wrote their const-correct code). Second, as I stipulated earlier, my users can't possibly care that the cache changed when Send() was called.

Part 2 of response...

Now for the example of how I used mutable.

I had a class that implemented a table control for our user interface. My table allows users to change the text in cells, or change the fonts in cells, etc. One of my goals in developing this class was to have my table class automatically compute the row heights and column widths necessary to be able to draw the cell text without clipping. Consequently, every time the user changes the font or changes text, I have to recompute the entire table size. This is a fairly expensive operation, and I did not want to incur that penalty.

Now my class also has a Size() method -- declared const -- that returns the actual height and width in pixels of the table. Obviously Size() doesn't change the fonts or colors or spacing or text or anything that the user cares about, so that's why it's const.

So how did I optimize my size calculations? I decided that my table class will keep two additional data members -- one for the row heights and one for the column widths. These members are calculated by the Size() method and stored internally in the object.
So my class looks something like:

[code]
class Table {
public:
size Size() const;
private:
int columns;
int rows;
CellData tableData[ 50 ][ 50 ]; // Data for each cell, such as text, font, color, etc.
mutable int rowHeights[ 50 ]; // I'm simplifying here... I never use arrays
mutable int colWidths[ 50 ]; // but that is another story.
};

Yes, there were other ways to do this. But I chose this way as the most readable/maintainable method for future programmers.

So to make the long story short, here's a brief summary:
0) See my above documentation on interpreting const when used to modify
variables.
1) const can be used to guarantee to your users that a member function
will not modify the object in any way the user could possibly care about.
2) The problems with not being const-correct are:
a) in many cases your users won't know if the member function modifies
state or you, as the programmer of the class, just were being sloppy and
forgot to declare the function const;
b) it makes writing const-correct code that uses your code almost impossible.
3) Sometimes (VERY RARELY) you might have a data member that your users
can't possibly care about, and you need to modify it inside a const member
function. This is when you declare the data member mutable.
Thank you about the explanation.

Your examples, jsmith, are very good so I can understand it. I don't need any code, just an example as you gave it.
Thank you again. :D
yes.. the examples and explanation were very good. I have definately walked away from this thread with new knowledge. and Am going to save most of what you said for refference so that I can glance back at it as needed.
Topic archived. No new replies allowed.