I've recently stumbled onto the following "loophole" around const-correctness:
struct Inner {
int field = 0;
void Modify() {
field++;
}
};
struct Outer {
Inner inner;
};
class MyClass {
public:
Outer outer;
Inner& inner; // refers to outer.inner, for convenience
MyClass() : inner(outer.inner) {}
void ConstMethod() const {
inner.Modify(); // oops; compiles
}
};
It further appears to be possible to use this loophole to modify an object declared as const
, which I believe is undefined behaviour:
int main() {
const MyClass myclass;
std::cout << myclass.outer.inner.field << "\n"; // prints 0
myclass.ConstMethod();
std::cout << myclass.outer.inner.field << "\n"; // prints 1
}
This scares me, because it seems like I've just invoked undefined behaviour related to const-correctness in a program that doesn't use const_cast
or cast away constness using a C-style cast.
So, my questions are:
Any modifications to a const
object is undefined behaviour, and the snippet does indeed do that.
The program isn't ill-formed (which would then require a compile error), since at the point of initializing inner
, cv-qualifiers haven't taken effect yet.
From the compiler's standpoint, to issue a warning would require it to analyze all code paths leading up to inner.Modify()
and proving that inner
must be referring to a const
object, which is impossible in the general case.
The best suggestion is likely to not have internal pointers/references, which are evil anyways.
That is not an error in code, remember that const refers to the innermost element of the declarator. Basically the const on ConstMethod makes the reference:
Inner& const inner;
Of course that does not make any real difference because references cannot be re-bound. Think of doing the same thing with a pointer instead and you would realize that inner could still be modified. If it were:
Inner * const inner;
you could call inner->Modify().
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