Data member of reference type provides “loophole” around const-correctness

  • A+
Category:Languages

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:

  • Am I correct to say that the above program has undefined behaviour?
  • If so, is this a language bug? Is there a line in the above program that arguably shouldn't (could reasonably made not to) compile?
  • Are there some guidelines that should be followed to avoid this category of undefined behaviour in practice?

 


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.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: