Is there UB in the code below?
#include <iostream>
int* p_n;
class A
{
public:
A(int val) : n(val)
{
// At this point the compiler does not know if the object is const or not.
p_n = &n;
}
int n;
};
int main()
{
// A::n is const, because A is const, right?
const A a(1);
// but we change a const value here
*p_n = 2;
std::cout << a.n << std::endl;
return 0;
}
Is there a difference between assigning *p_n and doing this?
const_cast<A&>(a).n = 2;
EDIT
From here:
const and volatile semantics (7.1.6.1) are not applied on an object under construction. They come into effect when the constructor for the most derived object (1.8) ends.
While object a is under construction, it is not const and a.n is not const, but they become const when the constructor ends.
So, does p_n point to the const object or not?
Yes. The code attempts to modify an int which is const. It does that by circumventing const-correctness, in the way you already discovered.
// A::n is const, because A is const, right? const A a(1);
Yes. a is const, hence a.n cannot be modified.
// but we change a const value here *p_n = 2;
Once you managed to bypass const and modify a.n, which cannot be modified, all bets are off. The code has undefined behavior.
is there a difference between assigning *p_n and doing this:
const_cast<A&>(a).n = 2;
No. const_cast does not change the fact that a is const.
Consider that you can have a pointer to const, or a const reference to an object that is not actually const, eg:
int x = 42;
const int& ref = x;
Here you could cast away constness from the reference to modify the integer. The integer is not const. Taking a const reference does not change that the object itself is not const. Similar in your example, no pointer hackery nor casts will change the constness of a.
Concerning your edit... It does not change the fact that a is const and that a.n once constructed is const. The quote you added merely explains the hole in const-correctness your code uses to invoke undefined behavior.
The reason const is only applied after construction is that otherwise a constructor that constructs a const object would be pretty useless. The constructor is needed to establish the class invariants, which typically requires to modify the object.
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