对临时字符串使用基于范围的循环时出现空字符?

Jus*_*tin 3 c++ string c++11

当我使用基于范围的 for 循环遍历临时std::string(右值?)时,似乎有一个额外的字符,即 null 终止符\0

当字符串不是临时的(而是左值?)时,没有多余的字符。为什么?

    std::map<char, int> m;

    for (char c : "bar") m[c] = 0;

    for (auto [c, f] : m) {
        if (c == '\0') std::cout << "this is a null char, backward slash zero" << std::endl;
        std::cout << c << std::endl; 
    }
Run Code Online (Sandbox Code Playgroud)

输出:

this is a null char, backward slash zero

a
b
r
Run Code Online (Sandbox Code Playgroud)

\0(注意正在打印的空行)

相比:

    std::map<char,int> m;
    
    std::string s = "bar";
    
    for (char c : s) m[c] = 0;    
    
    for (auto [c, f] : m) {
        if (c == '\0') std::cout << "this is a null char, backward slash zero" << std::endl;
        std::cout << c << std::endl; 
    }
Run Code Online (Sandbox Code Playgroud)

输出:

a
b
r
Run Code Online (Sandbox Code Playgroud)

son*_*yao 8

因为"bar"它不是一个std::string,而是一个包含 4 个元素的char数组 ( const char[4]) ,包括最后一个空字符。即c 风格的字符串文字

空字符('\0'L'\0'char16_t()等)始终附加到字符串文字中:因此,字符串文字"Hello"const char[6]保存字符'H''e''l''l''o'和 的'\0'

对于临时std::strings ,它将按您的预期工作,即不包含空字符。

for (char c : std::string{"bar"}) m[c] = 0;
Run Code Online (Sandbox Code Playgroud)

或者

using namespace std::string_literals;
for (char c : "bar"s) m[c] = 0;
Run Code Online (Sandbox Code Playgroud)

顺便说一句,@HolyBlackCat 建议您还可以使用std::string_view(自 C++17 起),当从 c 样式字符串文字构造时,它不会包含以 null 结尾的字符。例如

for (char c : std::string_view{"bar"}) m[c] = 0;
Run Code Online (Sandbox Code Playgroud)

或者

using namespace std::literals;
for (char c : "bar"sv) m[c] = 0;
Run Code Online (Sandbox Code Playgroud)

  • 还可以使用“string_view”来避免堆分配。 (2认同)