5

Recently I decided to dive into the C++ Standard and check whether certain code snippets are well defined and where to find those definitions in the standard. Since the standard is rather hard to get right (especially if you are not used to it) I wanted to verify if my assumption is right.

I came across the following example (which is obviously a bad idea). It compiles just fine (using g++ 8.2.1) but SEGFAULTs during execution:

#include <iostream>

static const int staticInt = 23;

int main () {
    int &localInt = const_cast<int &>(staticInt);
    localInt = 11;
    std::cout << staticInt << std::endl;
    return 0;
}

So, I searched through the standard (I use the working draft on open-std btw) and found paragraph 6.8.10:

Creating a new object within the storage that a const complete object with static, thread, or automatic storage duration occupies, or within the storage that such a const object used to occupy before its lifetime ended, results in undefined behavior.

Am I right, that this paragraph is applicable for the given example? If I am not, where else should I look at?

P.W
  • 26,289
  • 6
  • 39
  • 76
  • 2
    Your code does not create a new object within the storage of `staticInt`, so it can't possibly apply. – molbdnilo Feb 18 '19 at 10:08
  • 3
    The sections relevant to this problem is the ones about `const` variables. You attempt to modify a `const` variable, which leads to UB. End of story. That it is `static` or in the global scope or that you use a reference to the variable or that the reference is in a different scope is irrelevant. – Some programmer dude Feb 18 '19 at 10:09
  • @molbdnilo Assignment of a trivial type does create a new object in some cases. Not sure what those cases should be... – curiousguy Feb 20 '19 at 20:35

1 Answers1

9

This is undefined behavior because of the attempt to modify a const variable after using a const_cast on it.

Citations from n4659, the final working draft of C++17 . The relevant passage in this case is:

8.2.11 Const cast [expr.const.cast]
...
6 [ 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 ]

Also of relevance is this section related to const objects:

10.1.7.1 The cv-qualifiers [dcl.type.cv]
...
4 Except that any class member declared mutable can be modified, any attempt to modify a const object during its lifetime results in undefined behavior.

P.W
  • 26,289
  • 6
  • 39
  • 76
  • Well, that seems a lot more reasonable. Thanks for your answer. – Sebastian Kaupper Feb 18 '19 at 10:15
  • 5
    I think the [7.1.7.1p4](https://timsong-cpp.github.io/cppwp/n4618/dcl.type.cv#4) is more explicit: `...., any attempt to modify a const object during its lifetime results in undefined behavior.` – KamilCuk Feb 18 '19 at 10:17
  • @KamilCuk: Just added that. Thanks for mentioning it. – P.W Feb 18 '19 at 10:24
  • I'd swap your two quotes. `[dcl.type.cv]/4` is the reason OP's snippet is UB, `[expr.const.cast]/6` is "also relevant" ;) – YSC Feb 18 '19 at 10:35
  • @YSC: I wanted to do too that but then I realized that the code would not even compile without the `const_cast`. So I addressed that bit first. – P.W Feb 18 '19 at 10:45
  • IMO it doesn't make much sense. With the same reasoning, the code wouldn't compile without `[basic.def]` or most of the standard actually. Anyway, it's not that important, nice answer ;) – YSC Feb 18 '19 at 10:49