c++c++11constantsautocstring

Correct way to define a constant C-string in C++?


Most of the time I see constant C-strings defined as:

static char const* MY_CONSTANT = "Hello World";

However, the pointer itself is not const. Wouldn't it be more appropriate to do it like below?

static char const* const MY_CONSTANT = "Hello World";

There are 2 goals with constant globals like this, I think:

  1. Do not allow modification of the string
  2. Do not allow the variable to point to anything else

I simply assumed these 2 goals were needed when defining constant strings.

Another interesting thing is that I am allowed to do this:

int main()
{
    auto MY_CONSTANT = "";
    MY_CONSTANT = "Another String";
}

This tells me that auto deduces the string as char const* and not char const* const.

So I have two main questions:

  1. What is the most appropriate way to define constant c-style strings (I suppose constant pointers-to-something, is the more general question?). Why do you choose one or the other?
  2. Concerning my example with auto, it makes sense why it chooses char const* (because it's the array of data that's constant, not the pointer itself). Could I make auto deduce to char const* const or can I change the code to make it result in such a type?

Solution

  • Well if it a truly a constant then constexpr would be the C++11 way to do this:

    constexpr char const* MY_CONSTANT = "Hello World";
    

    The first example:

    static char const* MY_CONSTANT = "Hello World";
    

    just says I have a pointer to a char const that has static storage duration, which if it is outside of a function would make it a global.

    If we required the pointer to also be const then we need the second form your introduced. It all depends on whether the pointer is indeed supposed to const or not. In most cases, the reason your see code without the top-level const is because they just forgot to put it in not because they did not mean the pointer to also be const.

    Where static makes a difference for example if whether you want a const member to be per-instance or per-class:

    class A
    {
            char const* const const_per_instance = "Other Const String";
        public:
            constexpr static char const* const const_per_class = "Hello World" ;
    };
    

    If we require the const to be per-class then we need to use static otherwise not. The example changes slightly if you are not allowed to use constexpr:

    class A
    {
            char const* const const_per_instance = "Other Const String";
        public:
            static char const* const const_per_class  ;
    };
    
    char const* const A::const_per_class = "Hello World" ;
    

    but the essence is the same just the syntax is different.

    For your second question as Gotw #92 says auto drops top level const, one example given is as follows:

    const int   ci  = val;  
    auto        g   = ci;
    

    and it says:

    The type of g is int.

    Remember, just because ci is const (read-only) doesn’t have any bearing on whether we want g to be const. It’s a separate variable. If we wanted g to be const, we would have said const auto as we did in case c above

    the example that is being referred to is as follows:

    int         val = 0;  
    //..
    const auto  c   = val;