取消引用end()是否安全?

时间:2014-05-15 13:48:22

标签: c++ stl

我有一个带有以下签名的函数:

std::string f(const char *first, const char *last) {
    std::string result;
    std::for_each(first, last, some_lambda_which_appends_to_result);
    return result;
}

和std :: string的重载调用它:

std::string f(const std::string s) {
    return f(&*s.begin(), &*s.end());
    // The one below would assume that the string is not empty
    //     f(& s.front(), & s.front() + s.size());
}

然而,这可能是不安全的(取消引用s.end()本身可能是一张红牌攻击)。 是否有一种安全的方法来获取指向字符开头的指针和一个一个接一个的结束指针(如果是空字符串,两个空指针就可以了), 或者我必须写

std::string(const std::string& s) {
    return s.empty() ? std::string() : f(& s.front(), & s.front() + s.size());
}

2 个答案:

答案 0 :(得分:5)

取消引用end()是不安全的。但是,您可以使用c_str()data()来满足您的需求:

std::string(const std::string& s) {
    return f(s.data(), s.data() + s.size());
}

答案 1 :(得分:1)

根据C ++ 14标准(N4140),它是安全的。来自[string.accessors] / 1:

  

const charT* data() const noexcept;

     

1 返回:指针pp + i == &operator[](i)中的每个i [0,size()]

这保证了字符串有连续的存储空间,并且在字符串的最后一个字符之后存储了一个空终止符。

[string.iterators] / 2中end()的定义说:

  

2 返回:迭代器,它是过去的结束值。

"过去的价值"在[iterator.requirements.general] / 5中:

  

正如指向数组的常规指针一样,保证指针值指向数组的最后一个元素,因此对于任何迭代器类型,都有一个迭代器值指向相应序列的最后一个元素即可。这些值称为past-the-end值。定义了表达式i的迭代器*i的值称为可解除引用。库从不假设过去的值是可解除引用的。迭代器也可以具有与任何序列无关的奇异值。 [...]

看看这是如何谨慎对待说过去的结尾迭代器永远不会被解除引用。

粗体部分表示std::string::end()指向字符串的最后一个元素。根据上面的data()定义,这可以保证它指向空终止符。

由于没有任何地方可以说这个迭代器是单数和/或不可解除引用的,我们必须得出结论,就像所有其他迭代器一样,取消引用它会产生对它指向的字符的引用。