21

Our team is working with a 10+ years old C++ code base and recently switched to a C++17 compiler. So we are looking for ways to modernize our code. In a conference talk on YouTube I heard the suggestion, to replace const char* global strings with constexpr string_view.

Since we got quite a number of such const char* global string constants in our code, I want to ask if there are any gotchas or potential issues we need to be aware of?

PixelSupreme
  • 395
  • 2
  • 9

1 Answers1

19

These issues might be worth being aware of:

  1. std::string_view doesn't need to be null-terminated. So if you replace some const char* by string_view and replace the construction of a previously null-terminated char* substring by a string_view via std::string_view::substr, you can't pass the underlying pointer to an API that expects a null-terminated string. Example (without UB, but that is easily constructable, too):

    void legacy(const char *str) {
       std::printf("%s\n", str);
    }
    
    constexpr std::string_view sv1 = "abcde";
    constexpr std::string_view sv2 = sv1.substr(0, 2); // view on "ab"
    
    legacy(sv2.data()); // Not intended: prints "abcde" 
    
  2. While you can implicitly construct a std::string from a const char*, you cannot do that with a std::string_view. The idea is that a deep copy shouldn't happen under the cover, but only when explicitly requested. Example:

    std::map<std::string, int> m;
    constexpr std::string_view sv = "somekey";
    constexpr const char *old = "somekey";
    
    m[old] = 42; // works as expected
    m[sv] = 42; // fails to compile
    m[std::string(sv)] = 42; // be explicit, this is ok
    

    Depending on the existing usage of the global const char* instances in your project, this behavior might require manual intervention at various places.

lubgr
  • 37,368
  • 3
  • 66
  • 117
  • that non-zero termination is definately a gotcha - auch. Now I need to go through our SVs. I suppose you would do `std::string(sv).c_str()` instead for passing to API ? – darune Oct 08 '19 at 08:40
  • @darune That's an option, but then the lifetime assumptions of the API should be checked, right?! If you go with `someLegacyFct(std::string(sv).c_str())` and this backend somehow stores the pointer... – lubgr Oct 08 '19 at 08:45
  • that is correct - only with that lifetime assumption – darune Oct 08 '19 at 08:48
  • The second issue is "luckily" not going to be a big deal for us. Our company framework has it's own string class (I know...), with an explicit `const char*` constructor. So explicit construction of `std::string` from `string_view` would just be consistent in our case. – PixelSupreme Oct 09 '19 at 09:16