Every now and then I see people writing C++ code containing heresy in the vein of the following:
char * foo = "bar"; |
This is no more legal C++ than
const int qux = 42; int * quux = &qux; |
It is not undefined, unspecified or implementation defined! It is simply illegal (and conveys false intent: char* implies modifiable string). It should simply not compile, though right now all the major compilers let you get away with such a conversion – but they may (and should) stop that at any time.
It is valid in C (C89 through C11), although assigning to a string literal is undefined behaviour there. C++, however, has deprecated this conversion since C++98.
C++03 §4.2/2 (conv.array/2)
A string literal (2.13.4) that is not a wide string literal can be converted to an rvalue of type “pointer to char”; a wide string literal can be converted to an rvalue of type “pointer to wchar_t”. In either case, the result is a pointer to the first element of the array. This conversion is considered only when there is an explicit appropriate pointer target type, and not when there is a general need to convert from an lvalue to an rvalue. [Note: this conversion is deprecated. See Annex D. ]
In fact, the original proposal would be old enough to buy alcohol around the world this year, USA included! In my opinion, more than enough time has passed to phase out that “feature”. The C++ Standards Committee seems to agree, as C++11 doesn’t list such conversion at all (conv.array has only one sub point) and, in Annex C, says the following:
C.1.1 Clause 2: lexical conventions [diff.lex]
/…/
char* p = “abc”; // valid in C, invalid in C++
In C++, we’re years past writing such code (I hope). If you need a modifiable string, initialize an array or use std::string:
char foo[] = "bar"; // ok std::string qux = "quux"; // ok |
and if you don’t need to modify, for the sake of your co-workers (if not your own), don’t break const-correctness and use:
char const foo[] = "bar"; // ok, const array; be careful when using as a stack or non-static class member variable. char const * foo = "bar"; // ok, rebindable pointer char const * const foo = "bar"; // ok, non-rebindable pointer |
good one
very informative. better to learn that before this becomes a bad habit
This is very informative. Everyone should be aware of this.
Thanks for your effort writing this article.
Better: static const char* const foo = “bar”;
Good point, though it’ll be optimized out either way.
If I saw static I would be confused and think why does he use static here? Better use static only when it serves a purpose imho.
You write at the end:
and if you don’t need to modify, for the sake of your co-workers (if not your own), don’t break const-correctness and use:
char const * foo = “bar”; // ok
But this is not right either. Why are you declaring a pointer, and initializing it with the address of an literal ? The pointer itself is not const, so you might by mistake reassign it ( unless you DO want to reassign it, of course ). Each time you pass it somewhere, one additional level of indirection is involved,
Normally, to work with an string literal, you do not need a pointer
const char foo[] = “bar”;
Your point is valid most of the time, but you probably wouldn’t want to do that for stack/non-static class variables. That being said, I’ll be correcting my post to provide more refined suggestion. Thank you.