1

In C++, can the value of a const & change?

Well, of course it cannot change, can it? That's what const means. Moreover, listen to Stroustrup:

A const lvalue reference refers to a constant, which is immutable from the point of view of the user of the reference.

But what about this?

#include <iostream>

int main() {
    int           a = 0;
    const int&    r = a;
    const int old_r = r;
    ++a;
    const int new_r = r;
    std::cout
      <<      "old_r == " << old_r
      << " but new_r == " << new_r << std::endl;
    return 0;
}

On my machine, this outputs, old_r == 0 but new_r == 1.

That gets to my real question. In the above code, look at the line

    const int new_r = r;

Insofar as

  • the address &new_r is extracted neither on this line nor elsewhere in the code and
  • the code has nothing volatile,

does anything prevent an optimizing compiler from merging old_r and new_r into a single constant object, treating the line as though it read as follows?

    const int& new_r = old_r;

I ask because, as far as I know, if the compiler did so optimize, that might alter the behavior. The program might output, old_r == 0 but new_r == 0.

RELATED QUESTIONS

The most nearly related existing question I find is this one:

The following are also related but, unlike the present question, involve casts:

See also N4659 (draft C++17 standard), sect. 10.1.7.1, "The cv-qualifiers."

The quote of Stroustrup at the top of the question comes from sect. 7.7.2 of The C++ Programming Language, 4th ed. Of course, no author can write every sentence perfectly in a thousand-page book; yet perhaps Stroustrup is clear and I have merely read him wrong. Nevertheless, you might see why the sentence has confused me. This is why I have asked.

thb
  • 13,796
  • 3
  • 40
  • 68
  • 2
    Sure it can, and this is also one of the reasons `const T&` arguments make a function harder to optimize compared to passing the same arguments by-value. – You Feb 21 '19 at 16:06

4 Answers4

9

In C++, can the value of a const & change?

Yes, this is perfectly legal. Taking a const& to some variable doesn't stop that variable from being able to be modified, it just means you can't modify the variable through the reference. That means

int a = 42;
int const& b = a;
++a;
std::cout << a << " " << b;

will print

43 43

Had I tried to do

++b;

though that would be a compiler error as b's access to the value is const and ++ is a non const operation.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
4

Well, of course it cannot change, can it? That's what const means.

No, it isn't.

const means you can't change the thing. It doesn't mean it won't change. It doesn't mean it's a constant.

const just gives you an immutable view of a thing. There may be other views of that thing, and those may be mutable.

does anything prevent an optimizing compiler from merging old_r and new_r into a single constant object

Yes: the fact that one of them would have the wrong value.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • You have shown that my phrasing incorrectly expresses my intent. Thanks for the tip. I have reworded the relevant part of the question. – thb Feb 21 '19 at 16:32
  • It doesn't look like you've changed the premise of the question, which is that you think binding a `const` reference introduces a guarantee that the referent won't be changed. This was originally quite clearly stated but is now more subtle. If that's no longer the premise of the question then could you please clarify the rest of it also? Why would this be undefined behaviour? What do you think `const` does exactly? – Lightness Races in Orbit Feb 21 '19 at 16:37
  • No, you have correctly understood the premise. The original question attracted +2 upvotes but also -2 downvotes, unexplained. The edit is my blind attempt to make the question more bland so that downvotes do not bury it. Cheek earns downvotes on SO. That's all. – thb Feb 21 '19 at 16:48
  • You have already been generous with your time, so I would not further impose. However, were you inclined to edit the question, the edit would be appreciated. Sometimes it's hard to strike just the right tone. – thb Feb 21 '19 at 16:50
  • Heh, IRTA "you have _incorrectly_ understood the premise" first time around :P – Lightness Races in Orbit Feb 21 '19 at 16:51
  • 1
    Yeah I'd just put it back the way it was tbh. That statement you edited out (which I quoted) seems to be the absolute core of the question. – Lightness Races in Orbit Feb 21 '19 at 16:52
4

In C++, can the value of a const & change?

Yes, but not through that reference (ignoring mutable fields).

void foo(const int& c, int& mut) {
    std::cout << c << " ";
    ++mut; // changes `c` if &c == &mut
    std::cout << c << std::endl;
}

and

int a = 42;
foo(a, a); // 42 43

does anything prevent an optimizing compiler from merging old_r and new_r into a single constant object, treating the line as though it read as follows?

The as-if rule allows compiler to optimize if visible side effect are the same,
which is not the case here. So your "proposed merge of variable" in your code cannot be done fortunately.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Aha. I see. It's the visible side effect rule. I think that that makes sense. I had the idea that a `const &` ought to imply, semantically, that the symbol referenced an unchanging object, and that the compiler might rely on this implication. You say however that this is not the case. Except with locks and atomics in threaded code, I had never had reason to use a `const &` to a nonvolatile but nevertheless changing object. Your answer is therefore illuminating. – thb Feb 21 '19 at 16:42
  • Is there any way in C++ to invite a compiler to assume that an object identified via reference won't change, in cases where the programmer knows that to be the case? In C99, one could indicate that with a `const*restrict` pointer, but I'm unaware of any concept similar to `restrict` in C++. – supercat Feb 22 '19 at 19:33
  • @supercat: There are no `restrict` is the standard. (but compilers generally provide equivalent as `__restrict__`). – Jarod42 Feb 22 '19 at 20:23
2

Yes, the const values can change. When you do

const int&    r = a;

you are creating a reference to a const int. The code that gets to use this variable will not be allowed to change the value via the reference. But it in no way suggests that the value stored there will not change.

See it as a variable with read-only permission. Some other piece of code might have write access.

You should compare with constexpr which are truly constant expressions.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Jeffrey
  • 11,063
  • 1
  • 21
  • 42
  • 1
    The second sentence in this answer is already part of the confusion I believe, as a `const int` certainly cannot change - so why should it be able to change when you form a reference to it? (The "const int" in "reference to const int" is not exactly the same as the "const int" in a `const int`, see reference binding.) The distinction is very subtle so I would prefer to elaborate on this wording. – Max Langhof Feb 21 '19 at 16:21