C++11 §12.1/14:
During the construction of a const object, if the value of the object or any of its subobjects is accessed through an lvalue that is not obtained, directly or indirectly, from the constructor’s this pointer, the value of the object or subobject thus obtained is unspecified. [Example:
struct C;
void no_opt(C*);
struct C {
int c;
C() : c(0) { no_opt(this); }
};
const C cobj;
void no_opt(C* cptr) {
// value of cobj.c is unspecified
int i = cobj.c * 100;
cptr->c = 1;
// value of cobj.c is unspecified
cout << cobj.c * 100 << '\n';
}
Compiling the above example outputs 100
. My question is why is the value of cobj.c
should be unspecified when the initialization list sets it to 0
before entering constructor? How is this behavior different in case if a non-const object is used?
Genuinely const
objects may be treated by the compiler as legitimate constants. It can assume their values never change or even store them in const
memory, e.g. ROM or Flash. So, you need to use the non-const access path provided by this
as long as the object is, in fact, not constant. This condition only exists during object construction and destruction.
Offhand, I think there does not need to be a corresponding requirement for destructors because the object lifetime has already ended and cobj.c
is inaccessible as soon as the destructor for cobj
begins.
As Matthieu mentions, it is a strong "code smell" to be accessing an object besides through this
during construction or destruction. Reviewing C++11 §3.8 [basic.life] ¶1 and 6, it would appear that cobj.c
inside the constructor is UB for the same reason it is inside the destructor, regardless of the object being const
or §12.1/14, because its lifetime does not begin until initialization is complete (the constructor returns).
It might be likely to work, but it will ring alarms for good C++ programmers, and by the book it is illegal.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With