31 Intermediate The Hundred
Two Consts, Two Meanings
same keyword, two different locks
#include <iostream>
int main() {
char greeting[] = "hello";
char farewell[] = "goodbye";
const char* p = greeting; // two pointers, two consts...
char* const q = greeting; // ...so both are locked down, right?
p = farewell;
q[0] = 'H';
p[0] = 'J';
q = farewell;
std::cout << "p -> " << p << '\n';
std::cout << "q -> " << q << '\n';
}
Which two of those four assignments does the compiler reject?
Answer
Not the ones you'd guess. p = farewell; and q[0] = 'H'; are both fine — the program
prints p -> goodbye and q -> Hello. The rejected pair is p[0] = 'J'; and q = farewell;.
Why¶
Read the declaration right to left. const char* p is "p is a pointer to a char that
is const", so the characters are protected and the pointer is free to roam.
char* const q is "q is a const pointer to a char" — the pointer is frozen, while
the characters it names are fair game. GCC 11 says exactly that, one word apart:
main.cpp:13:10: error: assignment of read-only location ‘* p’
13 | p[0] = 'J';
main.cpp:14:7: error: assignment of read-only variable ‘q’
14 | q = farewell;
"Location" is the thing pointed at; "variable" is the pointer itself. The same asymmetry is
why char* s = "hi"; earns ISO C++ forbids converting a string constant to char*
(-Wwrite-strings, on by default) — a literal's characters are const, so only the first
form may point at one.
The fix¶
Spell out which half you meant — and note that const char* and char const* are the
identical type, so the second spelling makes the right-to-left reading literal:
const char* p = buf; // pointer to const char: repoint yes, write no
char* const q = buf; // const pointer to char: repoint no, write yes
const char* const r = buf; // both frozen: repoint no, write no
Takeaway: const applies to whatever is immediately to its left — unless it is
leftmost, in which case it applies to what is on its right.
Try it: g++ -std=c++17 main.cpp -o demo && ./demo — add -DSHOW_BUG to meet the two errors.