The pointer itself also has an address. It's one address more
than the array solution has. The array solution saves
sizeof(char*) bytes (or whatever) in the resulting object file
(or it is optimized away).
One less level of indirection can often help the optimizer.
But more generally, conceptually, I think of this as giving a
symbolic name to a string literal. The same as something like:
int const toto = 43 ;
gives a symbolic name to the int const. For the most part, in
fact, coming from C, I think of such const variables as
replacing a hash define. So instead of:
#define TOTO 43
#define TITI "Hello!"
I have:
int const toto = 43 ;
char const titi[] = "Hello!" ;
With exactly the same types I had with the #define.
Fundamentally, of course, one might question the wisdom of
defining any form of string constant in a header file. Unlike
the case of integral constants, and to a lesser degree, at least
on some architectures, floating point constants, there's not
much the compiler can do with the initialization value. So
something like:
extern char const titi[] ;
seems generally more appropriate in the header. With, in some
source file:
extern char const titi[] = "Hello" ;
(And I would usually prefer char const[] for this, rather than
std::string, to be clear of any order of initialization issues.)