std :: end for strings是否应该指向null终结符?

时间:2014-09-19 02:47:01

标签: c++ c++11 iterator

我注意到std::end在字符串或字符数组时总是会引用null终止符。我认为std::end应该引用最后一个有效元素后面的数组的结尾。 '\0'不被视为有效元素吗?它是阵列的一部分。以下是一些都返回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 == '\0') << "\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 == '\0') << "\n";

    char test[3] = {'h', '\0', 'e'};
    std::cout << (*std::end(test) == '\0');
    return 0;
}

1 个答案:

答案 0 :(得分:5)

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

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

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

请注意,std::end对所有数组的行为均匀。也就是说,如果我们有一个数组T a[N],则std::end(a)会返回a + N,无论Tchar还是a的内容是的。它不会给你字符串的结尾;它为您提供了数组的结尾。同样,返回值始终为a + N。没有例外!

对于std::string,有一个终止空字符,但它不被视为字符串的一部分。 (与其他角色不同,在未定义行为的痛苦下,您不能修改它。)如果您有

std::string s("hello");

然后s[5]将具有空字符的值,但正如我所说,它不被视为字符串的一部分:s被认为有五个字符,而不是六个字符。最好将std::string视为完全没有空终止。最后一个字符为s[4],其值为'o',而std::end(s)是仅在std::begin(s) + 4之后的迭代器,即std::begin(s) + 5

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