I believe the motivation is to permit the compiler to cache the values of const
objects (note that's const objects, not merely referands of pointers-to-const and reference-to-const), and the addresses of referands of references, across calls to unknown code.
In your second example, the compiler can "see" firstly that the object has been created and destroyed, and secondly that it was re-created using the same value. But the authors of the standard wanted compilers to be allowed to turn this code:
struct Foo {
const int & x;
Foo (int & i) : x(i) {}
};
int i = 1;
Foo f(i);
some_function_in_another_TU(&f);
std::cout << f.x;
Into this:
struct Foo {
const int & x;
Foo (int & i) : x(i) {}
};
int i = 1;
Foo f(i);
some_function_in_another_TU(&f);
std::cout << i; // this line is optimized
because the reference member of f
cannot be reseated, and hence must still refer to i
. The destruct-and-construct operation violates the non-reaseatable-ness of the reference member x
.
This optimization should not be particularly controversial: consider the following example, using a const
object rather than an object with a const
or reference member:
const int i = 1;
some_function_in_another_TU(&i);
std::cout << i;
Here i
is a compile-time constant, some_function_in_another_TU
cannot validly destroy it and create another int
in its place with a different value. So the compiler should be allowed to emit code for std::cout << 1;
The idea is that the same should be true by analogy for const objects of other types, and for references.
If a call to unknown code could reseat a reference member, or alter the value of a const
data member, then a useful invariant of the language (references are never reseated and const objects never change their values) would be broken.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…