8

This is a language lawyer question, not a good practice question.

Is the following code valid or undefined behaviour? A const object ends up calling a non-const function, but it doesn't actually modify the state of the object.

struct Bob
{
    Bob() : a(0) {}

    int& GetA()
    {
        return a;
    }

    const int& GetA() const
    {
        return const_cast<Bob&>(*this).GetA();
    }

    int a;
};

int main()
{
    const Bob b;
    int a = b.GetA();
}
Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
Neil Kirk
  • 21,327
  • 9
  • 53
  • 91
  • This is, IMO, one of the few legitimate uses for `const_cast` (but I don't have a standard quote handy to prove it's allowed). – dlf Aug 20 '14 at 14:08
  • It might be legitimate, but I just don't see a reason for it. – Some programmer dude Aug 20 '14 at 14:09
  • @JoachimPileborg Here's [the question which started it](http://stackoverflow.com/q/25405135/1782465). – Angew is no longer proud of SO Aug 20 '14 at 14:09
  • @JoachimPileborg this factorizes the definition of `GetA`. Slight advantage, but advantage nonetheless. – Quentin Aug 20 '14 at 14:10
  • 1
    @JoachimPileborg Here no, but if the nonconst `GetA()` was doing nontrivial work, this could save repeating that code in the const version. – dlf Aug 20 '14 at 14:10
  • Related post: http://stackoverflow.com/questions/123758/how-do-i-remove-code-duplication-between-similar-const-and-non-const-member-func – juanchopanza Aug 20 '14 at 14:12
  • 5
    FWIW, in Effective C++, Scott Meyers suggested the opposite. In the non-const version, `return const_cast(static_cast(*this).GetA());` – chris Aug 20 '14 at 14:13
  • Only actual modification of `b` through `GetA() const` is undefined. Mere `const_cast` not used to actually modify anything is perfectly OK. – n. m. could be an AI Aug 20 '14 at 14:15
  • 4
    Doing it the other way like Scott Meyers suggest (according to @chris) might be a safer alternative, because one would know that the constant version of the function would not modify `this`, while there is no such guarantee with the non-constant function. A little mistake in the non-constant `GetA` and you will have UB. – Some programmer dude Aug 20 '14 at 14:16
  • 1
    @JoachimPileborg Of course, that one fails when the `const` version returns a reference to something that is actually declared `const`. – Angew is no longer proud of SO Aug 20 '14 at 14:32
  • @Angew, Right. I believe the advice was to use it for pairs of functions that had the same body. Functions where they should really both do the exact same thing. IIRC, the example in the book was `operator[]`. – chris Aug 20 '14 at 14:47
  • @chris Of course, that's where I use it as well. My point is that both of them can violate const correctness when used incorrectly, and the one in this question at least requires just one cast, not two. Still, I wouldn't object against code using either one. – Angew is no longer proud of SO Aug 20 '14 at 14:52
  • @Agnew That is true, but I suspect cases where you need a nonconst getter function for something that is actually declared const occur rarely (though not never). – dlf Aug 20 '14 at 15:36

2 Answers2

9

The behavior is well-defined :

C++ standard, section § 5.2.11/7 [const cast]

[ Note: Depending on the type of the object, a write operation through the pointer, lvalue or pointer to data member resulting from a const_cast that casts away a const-qualifier may produce undefined behavior. —end note ]

GetA() does not write any member of Bob, so this program does not involve undefined behavior.

AndyG
  • 39,700
  • 8
  • 109
  • 143
quantdev
  • 23,517
  • 5
  • 55
  • 88
4

I believe it is well-defined, since the standard only ascribes undefined behaviour to modifying a const object. C++11 quotes follow:

[expr.const.cast] 5.2.11 §7

[ Note: Depending on the type of the object, a write operation through the pointer, lvalue or pointer to data member resulting from a const_cast that casts away a const-qualifier may produce undefined behavior (7.1.6.1). —end note ]

[dcl.type.cv] 7.1.6.1 §4

Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior. ...

GetA() does not actually modify any object, so it doesn't have undefined behaviour.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • 1
    (note that `GetA()` could modify some objects and be well-defined, as long as no data members are involved) – quantdev Aug 20 '14 at 14:14