-4

In my book of c++ I just found a code where the book says there is an undefined behaviour.

# include <iostream>
using namespace std;

int main( )
{
const char * a = "aaa";
char * b = const_cast<char *>(a);
cout << a << '\n' << b << '\n';
b[0] = 'b'; // here undef. behaviour 
cout << a << '\n' << b << '\n';
}

I don't understand why . Does anyone know it ?

Jarod42
  • 203,559
  • 14
  • 181
  • 302
Jatos
  • 333
  • 2
  • 13
  • 8
    Do you understand the nature of `const_cast` and what it's doing here? – François Andrieux Aug 20 '19 at 18:27
  • 6
    String literals cannot be changed. This code attempts to modify a string literal. Therefore it's undefined behaviour. – john Aug 20 '19 at 18:30
  • In the same way as `const int i = 42; int& j = const_cast(i); j = 0;` – Jarod42 Aug 20 '19 at 18:32
  • Short answer - because you modify constant data, you are only allowed to modify data after const cast when original data is not const. – Slava Aug 20 '19 at 18:49
  • 1
    If the book doesn't tell you why, it's not a very good book. [Here](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) is a list of decent books. – molbdnilo Aug 20 '19 at 19:08

1 Answers1

4

String literals are immutable, so they're supposed to be stored in variables of const char *, to prevent accidentally trying to change them. The const_cast removes this layer of protection, and then b[0] = 'b'; is performing a write to it. Since it's still a string literal that it's pointing to, this write is undefined behavior.

  • 5
    Nit pick: string literals are `const char[N]`, not `const char *` – NathanOliver Aug 20 '19 at 18:34
  • 1
    You could elaborate on the possible reasons. E.g. the compiler is allowed to reuse the string if another constant has the same text. The compiler could even produce code that generates the string, so there might not even be a memory location for the text. The text could be stored on read-only media. – Jeffrey Aug 20 '19 at 19:21
  • @NathanOliver: I know of only one case where that's relevant, but it's a useful one: applying the `sizeof` operator on a string literal will yield a value one higher than its length. This makes it possible to define a macro to declare something like `static struct { uint16_t lengh, char dat[sizeof ("" LITERAL "")]} NAME = {sizeof ("" LITERAL ""), LITERAL} NAME;`, though unfortunately that can only be done at statement level, not expression level. – supercat Aug 21 '19 at 15:35