为什么std :: begin和std :: end"不是内存安全"?

Dav*_*rcz 54 c++ iterator std c++11

在这篇博客文章中,Eric Niebler表示:

std :: begin和std :: end有什么问题?惊喜!他们不安全.考虑一下这段代码的作用:

extern std::vector<int> get_data();
auto it = std::begin(get_data());
int i = *it; // BOOM
Run Code Online (Sandbox Code Playgroud)

std :: begin对const和非const lvalues有两个重载.麻烦的是,rvalues绑定到const左值引用,导致上面的悬空迭代器.

我无法理解他的观点,为什么it是一个悬垂的参考.有人能解释一下吗

Som*_*ude 59

该get_data函数返回一个对象.当按照所示方式使用时,该对象将是一个临时对象,一旦完整表达式结束,它将被破坏.迭代器现在引用一个不再存在的向量对象,并且不能以任何有用的方式解除引用或使用它.

  • 因为`std :: begin` _lets_你犯了这个错误,但`std :: ranges :: begin`不会. (18认同)
  • 虽然这绝对是正确的,约翰对原帖的评论也不合适吗?给定的例子如何显示std :: begin和std :: end的问题? (16认同)

Sto*_*ica 52

我认为Eric的观点std::begin是它默默地接受一个rvalue容器作为开头的参数.从表面上看,代码的问题也在中

auto it = get_data().begin();
Run Code Online (Sandbox Code Playgroud)

但是它std::begin是一个自由函数模板,可以使它拒绝rvalues而无需为每个容器的begin成员添加适当的引用限定符.通过"只是"转发,它错过了为代码添加一层内存安全性的机会.

理想情况下,过载集可能会从增加中受益

template< class C > 
void begin( C&& ) = delete;
Run Code Online (Sandbox Code Playgroud)

那个会导致博客文章中的代码被当场拒绝.

  • @PaulStelian - 这是怎样btw,纯C++ 14.http://coliru.stacked-crooked.com/a/7c99059b5b1a8dca (4认同)
  • @PaulStelian - 不,我们不能.我有意在另一个命名空间中提供了一个示例.要添加此重载,我们需要编写提案,然后将其投票到标准中. (3认同)
  • 事情是,正如亚历山大雷斯库在[2018年的cppcon]中幽默地指出它(https://www.youtube.com/watch?v=PH4WBuE1BHI"CppCon 2018 --- Andrei Alexandrescu,博士,布加勒斯特,2018- 10-01,期待预期的")谈话,C++委员会喜欢在过去的错误中保持一致.有人可能认为`std :: begin`接受_r-values_的原因是让`begin(c)`和`c.begin()`完全等价.(但是显然这个过载设置是理想的) (3认同)
  • @YSC` .begin()`也可以拒绝rvalues,不是吗?`iterator begin()&& = delete;` (3认同)

Jes*_*uhl 13

完成get_data后返回的临时向量超出范围std::begin.它不是活着的,所以它是it一个被破坏的物体的迭代器.