替换全局常量字符数组为constexpr string_view有什么需要注意的地方吗?

21

我们的团队正在使用一个超过10年的C++代码库,并且最近切换到了C++17编译器。因此,我们正在寻找现代化我们的代码的方法。在YouTube上的一次会议讲座中,我听说建议用constexpr string_view替换const char*全局字符串。

由于我们的代码中有很多这样的const char*全局字符串常量,我想问一下是否有任何需要注意的问题或潜在问题?

1个回答

19

以下问题值得关注:

  1. std::string_view 不需要以 null 终止。因此,如果您将某些 const char* 替换为 string_view,并通过 std::string_view::substr 将之前以 null 结尾的 char* 子字符串的构造替换为 string_view,则无法将底层指针传递给期望 null-terminated 字符串的 API。例如(没有 UB,但很容易构造):

    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. 虽然你可以从const char*隐式构造一个std::string,但你不能这样做来构造一个std::string_view。这是因为深复制不应该在幕后发生,只有在显式请求时才会发生。例如:

  3. 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
    

    根据您项目中全局 const char* 实例的现有用法,此行为可能需要在各处进行手动干预。


非零终止符确实是一个坑点 - 哎呀。现在我需要检查我们的SVs。我想你会使用std::string(sv).c_str()来传递给API吧? - darune
@darune 这是一个选项,但是API的生命周期假设应该被检查,对吧?!如果你选择 someLegacyFct(std::string(sv).c_str()) 并且这个后端以某种方式存储指针... - lubgr
只有在那个生命周期的假设下才是正确的。 - darune
第二个问题对我们来说“幸运”的是不会成为一个大问题。我们公司的框架有自己的字符串类(我知道...),具有显式的const char*构造函数。因此,在我们的情况下,从string_view显式构造std::string将是一致的。 - PixelSupreme

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接