Where does const go in CPP

2017/01/15

A word of warning at the beginning: This post is about C++, not about C and I will not explain the basics of pointer arithmetics! So whatever you read here may not necessarily apply to C. Nevertheless you may have a look Sugih’s page which features are in C.

Introduction

While writing C++11 code I was faced with the task of passing variables to functions which will not alter these. Or pure getter methods. And after reading a post about C++ constness I was left with more questions than really understanding. A quick search revealed thorough FAQ about const usage in C++. Here I’d like to make a short round-up of it.

How to read const

First of all, read it from right-to-left. For instance int const* const p would be read as “p is a constant pointer to a constant int”.

A few examples

string const& s

Let’s say you read something like this:

void MyClass::func (std::string const& s);

So reading from right-to-left this would say “s is reference to a constant std::string”. This implies that func is not going to modify s. But keep in mind that you may have a dangling reference here, especially if you work with multi-threaded code. If this would be a pointer instead of a reference it is still possible the pointer to be NULL.

string* const s

void MyClass::func (std::string* const s);

Again, read from right-to-left: “s is a constant pointer to a string”. s may be modified (the object itself) but s may not point to a different object. As you may have already noticed it’s not that hard to read when you stick to the “read from right-to-left” rule.

string const* const s

void MyClass::func (std::string const* const s);

This would read “s is a constant pointer to a constant string” and therefore the function guarantees (respectively the compiler enforces it) that the content of s may not be changed nor may s point to a different object.

string const& const s

A signature as followed

void MyClass::func (std::string const& const s);

is non-sense in term of that references can never be re-assigned and therefore is redundant.

Similar consts

Obviously some signatures mean the same thing:

void MyClass::func (const std::string& s); // you may know this from C
void MyClass::func (std::string const& s);

void MyClass::func (const std::string* s);
void MyClass::func (std::string const* s); // equivalent
void MyClass::func (std::string* const s); // Pitfall: NOT equivalent

Now, it doesn’t matter which version you use but is more a decision you have to make. If previously written code opts for one variant you should for the sake of consistency use the same way. But if you want to use the handy right-to-left rule you may consider the first variant, which in my personal opinion is better for beginners.

Methods that do not change its object

When you write a pure getter method you may want to tell your compiler that the following code may not change the object itself.

std::string const& MyClass::func () const;

The last const indicates that this function may not alter its objects data.

Advanced constness

The mutable keyword

Let’s say that you want to count how many times your getter method was called but you want to declare your method to be const. How would you do that? Well, that’s how it would work:

#include <iostream>

class MyClass
{
private:
    std::string s;
    mutable int count;
public:
    MyClass();
    ~MyClass();
    std::string const& get_string() const;
    int get_count();
};

MyClass::MyClass () {
    s = "Hello World!";
    count = 0;
}

MyClass::~MyClass () {}

std::string const& MyClass::get_string() const {
    count++;
    return s;
}

int MyClass::get_count() {
    return count;
}

int main () {
    MyClass o;
    
    for (int i = 0; i < 5; ++i)
    {
        std::cout << "\"" << o.get_string() << "\"" << \
            " was accessed " << o.get_count() << " times." << std::endl;
    }

    exit (0);
}

Which executed does this:

$ ./mutable 
"Hello World!" was accessed 1 times.
"Hello World!" was accessed 2 times.
"Hello World!" was accessed 3 times.
"Hello World!" was accessed 4 times.
"Hello World!" was accessed 5 times.

One more thing: MyClass** → MyClass const**

There is one more thing which is hard to understand and Marshall Cline does a better job at explaining it than I will ever be able to do: Why am I getting an error converting a Foo** → Foo const**?

Final words

A big thank you to Marshall Cline which is a master mind in explaining complex things! And also thank all these people who I bothered so much while writing code.