在`abcd`和`abc`的情况下,`std :: equal`是否取消引用`end()`?

时间:2016-01-07 02:14:31

标签: c++ stl

基于http://en.cppreference.com/w/cpp/algorithm/equalstd::equal的实施如下:

    template<class InputIt1, class InputIt2>
    bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2)
    {
        for (; first1 != last1; ++first1, ++first2) {
            if (!(*first1 == *first2)) {
                return false;
            }
        }
        return true;
    }

当我将string str1 = "abcd"string str2 = "abc"进行比较时,equal(str1.begin(), str1.end(), str2.begin())会按预期返回false。由于abcd只有一个字符,我想知道上述实现是否将'd'*str2.end()进行了比较。看起来是这样,但不是不安全吗? str2.end()可能指向任何内容,可能是'd'

3 个答案:

答案 0 :(得分:4)

假设您正在谈论std::stringstd::wstring,并假设您正在讨论不包含嵌入空值的字符串(如示例中的文字)。然后:

由于C ++ 11解除引用end()实际上保证为非const实例产生null-char值。所以比较在那里停止,因为它与此时的另一个字符串的值不同,或者它是最后一个迭代器位置。

C ++11§21.4.5/ 2
std::basic_string::operator[]
  

返回*(begin() + pos) if pos < size(),否则引用T类型的对象,其值为{{1} }};参考值不得修改。

对于语言律师来说,这里有一个很好的点,即charT()定义了空值效应,operator[]是根据end以外的迭代器定义的,因此end迭代器原则上可以是特殊的。

但这显然违背了尽可能提供C字符串语义的意图。

答案 1 :(得分:2)

在这种情况下,您将五元素数组与四元素数组进行比较(C风格和C ++风格的字符串都具有终止NUL字符),第四个元素不同。

如果您改为

char str1[4] = { 'a', 'b', 'c', 'd' };

char str2[3] = { 'a', 'b', 'c' };

然后你的调用将执行超出边界的读取(未定义的行为)。

答案 2 :(得分:1)

是的,确实如此。这就是为什么在C ++ 14中,委员会添加了equal(以及mismatchis_permutation)的“四个迭代器”版本。

equal(s1.begin(), s1.end(), s2.begin(), s2.end())

不会取消引用s2.end()(并且如果范围大小不同,可以快速返回false,以启动!)