Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can reference members be modified by const member functions?

Tags:

c++

The following will compile even though a const member function will modify the value of a member. How so ?

#include <iostream>

struct foo
{
    std::string &str;
    foo(std::string &other) : str(other) {}

    void operator()(std::string &some) const
    {
        str += some;
    }
};

int main()
{
    std::string ext("Hello");
    foo a{ ext };

    std::string more(" world!");
    a(more);

    cout << a.str;
    return 0;
}
like image 763
Nikos Athanasiou Avatar asked May 02 '14 20:05

Nikos Athanasiou


2 Answers

The const qualifier of a class member function indicates that this member function (e.g., foo::operator() const) cannot change the state of the object from the client's point of view (i.e., it's abstract state). This is not exactly the same as saying that the object's raw bits are not going to change.

It is forbitten to C++ compilers to consider objects as raw bits, unless they can resolve the problem of aliasing. which in your case the compiler cannot. This is due to the fact that a non-constant alias exists (i.e., std::string &str) and consequently the state of the object is modifiable.

That is, calling operator() on object a does not change the state of a (i.e., although ext has changed, the str still remains an alias of ext).

The above also explains why pointing at an object with a pointer to constant (i.e., std::string * const str) does not guarantee that the object won't be modified. It only guarantees that the object won't change through that pointer.

like image 58
101010 Avatar answered Nov 04 '22 06:11

101010


Consider the reference like a classic pointer:

#include <iostream>

struct foo
{
    std::string * const str; // is the same as std::string &str
    foo(std::string &other) : str(&other) {}

    void operator()(std::string &some) const
    {
        *str += some;
    }
};

int main()
{
    std::string ext("Hello");
    foo a{ ext };

    std::string more(" world!");
    a(more);

    cout << a.str;
    return 0;
}

You'll see that the pointer doesn't change, only the value pointed by it does.

like image 20
nouney Avatar answered Nov 04 '22 08:11

nouney