【问题标题】:Is an Iterator to vec.end() still valid after vec.push_back() when there is no reallocation当没有重新分配时,vec.end() 的迭代器在 vec.push_back() 之后是否仍然有效
【发布时间】:2011-03-22 19:21:14
【问题描述】:

此示例代码有效吗?

#include<vector>
using namespace std;

int main() {
  vector<int> vec(10); // create with 10 elements
  vec.reserve(100);    // set capacity to 100
  vector<int>::iterator iter = vec.end(); // points 1 past vec[9]

  vec.push_back( 777 );

  bool is_this_valid_and_true =  *iter == vec[10]; // ?

  // VS2010 runtime error in debug build:
  // Expression: vector iterator not dereferencable
  // Works in release build

  iter = vec.end() + 1; // points 2 past vec[10]?
  vec.push_back( 888 );
  vec.push_back( 999 );

  is_this_valid_and_true =  *iter == vec[12]; // ?
}

VS2010的错误可能和这个bug有关。

如果我设置命令行选项/D_HAS_ITERATOR_DEBUGGING=0 或设置

#define _HAS_ITERATOR_DEBUGGING 0
#include<vector>

没有错误。

编辑:

根据答案,我认为这段代码应该会导致错误。编译器中没有错误。它只在发布模式下工作,因为迭代器被实现为指针。

【问题讨论】:

  • 没有错误。有错误(它只是沉默而致命,稍后会用飞鼻恶魔杀死你)。

标签: c++ iterator


【解决方案1】:

23.2.4.3/1:

如果新大小为 大于旧容量。如果不 重新分配发生时,所有 迭代器和引用之前 插入点保持有效。如果 引发异常 复制构造函数或赋值 T 的运算符没有效果。

所以不,end() 不必在push_back 之后有效。引用与vector.insert相关,push_back定义为insert

【讨论】:

  • 感谢参考标准。我看的时候不知道在哪里可以找到相关信息。
【解决方案2】:

您将迭代器视为指针。

迭代器可以使用指针作为实现细节,但它们不是实际的指针。

因此:

iter = vec.end() + 1; // This is not valid.

不存在两个元素通过数据末尾的事情。

vec.end() 返回一个迭代器,当递减是对最后一个元素的引用(假设有元素)。而在递增时引用最后一个元素的迭代器等价于 end() 返回的迭代器。

// Note: Assuming vector iterators were not invalidated after an insert anyway.
//       But for arguments sake lets play this out.
//
vector<int>::iterator iter = vec.end(); // points 1 past vec[9]
vec.push_back( 777 );
bool is_this_valid_and_true =  *iter == vec[10]; // Not valid.
                                                 // This is the end() iterator
                                                 // de-referencing it is UB

但是取消引用 end() 表示的迭代器是未定义的 behavior() (即使您有保留空间)(实现可能不使用指针。例如,一些 DeBug STL 实现将在迭代器代码)。

【讨论】:

  • 谢谢。那么技巧iter=vec.end(); iter--; vec_push_back(777); iter++; 会使iter 成为现在最后一个元素的有效迭代器?
  • @JohnPS:只要没有重新分配,是的。
  • 所以,为了调试,我猜编译器将一个迭代器标记为无效,只要它在插入期间为== end()。之后的任何修改或算术都会导致调试错误。感谢您的澄清。
  • @JohnPS:我个人不会依赖它。但根据(非佳能)SGI 文档,它应该是好的:sgi.com/tech/stl/Vector.html(见底部的第 5 点)。至于调试 API 的工作原理,您需要查看 STL 的文档。
  • 其实,这是一个简单的修复(我认为)。只需push_back(),然后将我的迭代器设置为end()-1,而不是将其设置为end(),然后执行push_back()
猜你喜欢
  • 2021-09-24
  • 1970-01-01
  • 2019-04-06
  • 1970-01-01
  • 1970-01-01
  • 2018-03-11
  • 2012-09-01
  • 1970-01-01
  • 2016-12-12
相关资源
最近更新 更多