字符串的std::end应该指向null终止符之后

Should std::end for strings point past null terminator?

本文关键字:null 终止 之后 std end 字符串      更新时间:2023-10-16

我注意到,当涉及到字符串或字符数组时,std::end总是引用null终止符。我认为std::end应该指最后一个有效元素后面的数组的末尾。''是否被视为无效元素?它是数组的一部分。以下是一些全部返回true的测试:

#include <iostream>
int main()
{
    std::string s("hello!");
    auto s_end = *(s.data() + s.size() + 1);
    std::cout << std::boolalpha  << (*std::end(s) == s_end) << "n"
              << (s_end == '') << "n";
    char buf[6 + 1];
    std::copy(s.begin(), s.end(), &buf[0]);
    auto buf_end = *(buf + s.size() + 1);
    std::cout << (*std::end(buf) == buf_end) << "n"
              << (buf_end == '') << "n";
    char test[3] = {'h', '', 'e'};
    std::cout << (*std::end(test) == '');
    return 0;
}

对于字符数组,std::end确实指向数组中的最后一个字符。对于

char test[3] = {'h', '', 'e'};

指针CCD_ 5与CCD_。取消引用它与评估test[3]相同。这是未定义的行为。在您的特殊情况下,它恰好产生了''。但总的来说,它可能会产生不同的价值,或者崩溃,或者完全其他的东西。std::end(test)不指向数组test中索引1处的''字符!

注意,std::end相对于所有阵列表现一致。也就是说,如果我们有一个数组T a[N],那么无论Tchar还是a的内容是什么,std::end(a)都会返回a + N。它不会给你字符串的结尾;它给出了数组的末尾。同样,返回值始终为a + N。没有例外!

对于std::string,有一个终止的null字符,但它不被视为字符串的一部分。(与其他角色不同,你不允许修改它,因为行为不明确。)如果你有

std::string s("hello");

那么s[5]将具有null字符的值,但正如我所说,它不被视为字符串的一部分:s被视为具有五个字符,而不是六个字符。最好将std::string视为根本没有null终止。最后一个字符是值为'o's[4],而std::end(s)是刚好经过std::begin(s) + 4的迭代器,即std::begin(s) + 5

这比看起来更微妙,因为标准在技术上根本不能保证std::end(s)是可取消引用的,所以你不一定说它指向终止的null。在实践中,它确实指向终止null,但取消引用它仍然是未定义的行为。