I need to define several constant strings that will be used across an entire C++20 project.

I am considering the following options :

constexpr char[] str1 = "foo";
constexpr std::string str2 = "foo";
constexpr std::string_view str3 = "foo";

but I hesitate about which one I must choose.

constexpr char[] is efficient but is not modern C++.

constexpr std::string is modern C++ and takes advantage of the fact "since C++20 std::string is a constexpr class to perform operations at compile time" but even so, I heard it uses dynamic allocation anyway so it may not be the best option.

constexpr std::string_view is probably the optimal choice but I have checked several resources including Professional C++ (5th Edition) by Marc Gregoire and I didn't find clear guidelines it was the recommended way to define global constant strings. I just read it was the best choice to pass a read-only string to a function (compared to passing const std::string& or const char*).

So which technique is the right one for C++20 ?

8 Replies 8

Note, char[] str1 = "foo" is not a string. constexpr std::string str2 = "foo" is not a constant expression if a string is longer than some limit.

As always, the best choice depends on usages. If you going to pass those strings to a C API, then the first one is the only option.

I am asking this question for a project that uses only C++20, with no previous versions of C++ or C.

There is no best, personally I often use constexpr std::string_view str2{"foo"}; since std::string isn't constexpr in anything before C++20 (and we do have pre C++20 code). I don't use const char* to avoid "pointer" like types in C++

Your other option is C++ extern. I has it's heritage in C, but allows a global declaration in one source (translation unit) to be used throughout your project. (language linkage) Note the limitations Storage class specifiers

There is no best solution. The intuitive way is std::string_view. I always recommend using std::literals, because then you can simply write: auto str="str"sz; with deferred type deduction. If the constants are organized as an array:

using std::literals;
constexpr static std::array str_arr {
    "str 0"sv,
    "str 1"sv,
    "str 2"sv
};

Depending on the code and compiler this may increase your binary size by a few bytes. If that matters, then you need to define a string_list class of your own, with constexpr constructor, and desired properties.

std::string may be more efficient iff the string constants are short(less than 16 bytes in size). But there's unfortunately no std function that tells the short string maximum size. But if you can confirm the shortness criteria, then UDLs make code simpler to write again:

using std::literals;
constexpr static std::array str_arr {
    "str 0"s,
    "str 1"s,
    "str 2"s

I never recommend raw character arrays as string literals in C++. Aside from the decay problems associated with all raw arrays, raw character arrays have ambiguous usage; null-terminated string vs array of character values. This ambiguity may result in unpleasant surprises. Therefore, I always encourage using UDLs; sv for string_view and s for std::string. If you need arrays, std::array is available. Don't use the ambiguous raw character array literals, unless initializing an array like: std::array{"array ends in null"}.

A static constant array of characters can be placed in the Read-Only section of your executable. The array doesn't need to be created at runtime. Embedded systems can reference the data directly, no need to make copies.

Do you want to expose the fact that the string ends with \0?

Your Reply

By clicking “Post Your Reply”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.