12

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;
}
Nikos Athanasiou
  • 29,616
  • 15
  • 87
  • 153
  • 6
    It modifies what the member refers to, it does not modify the member. – brian beuning May 02 '14 at 21:01
  • 2
    Because it won't modify the reference itself. After applying the `+=` operator, the reference does not change, only the internal string contents do (in the context of the string, `this` is still the same). – Frédéric Hamidi May 02 '14 at 21:01
  • Try it with std::string* instead of & and you'll see the same thing. – dlf May 02 '14 at 21:04
  • 2
    It's called bitwise `const`, which is what C++ enforces, as opposed to logical `const`. See [this question](http://stackoverflow.com/questions/3830367) and [this one](http://stackoverflow.com/questions/8556794). – Oktalist May 02 '14 at 21:07

2 Answers2

12

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.

sehe
  • 374,641
  • 47
  • 450
  • 633
nouney
  • 4,363
  • 19
  • 31
2

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.

101010
  • 41,839
  • 11
  • 94
  • 168