c++迭代器随机失效

C++ Iterator randomly gets invalidated

本文关键字:随机失效 迭代器 c++      更新时间:2023-10-16

我迷路了:std::string的vector迭代器工作完美,除非在它之前有一个函数调用(Z_UB->set())。下面是代码:

std::vector< std::string >::iterator it = g_SPP.scenarios->getVector().begin();
std::cout << "begin of vector: " << *it << std::endl;
Z_UB->set("s1", "scn2", 350);
it++;
std::cout << "second of vector: " << *it << std::endl;

创建如下输出

begin of vector: scn1

但是,如果我像这样移动函数调用:

std::vector< std::string >::iterator it = g_SPP.scenarios->getVector().begin();
std::cout << "begin of vector: " << *it << std::endl;
it++;
std::cout << "second of vector: " << *it << std::endl;
Z_UB->set("s1", "scn2", 350);

结果如下,这是预期的行为:

begin of vector: scn1
second of vector: scn2

在Z_UB->set()函数内部,除了调用本身之外什么都没有剩下:

void Parameter::set( std::string _i, std::string _j, float value) {
//int i = indexSets[0]->backIndex(_i);
//int j = indexSets[1]->backIndex(_j);
//data2D[0][0] = value;
}

因此,如果在创建迭代器之后调用Z_UB->set()函数,访问它将使程序崩溃。关于迭代器,我还遗漏了什么重要的东西吗?

几种可能性:

  • 或者你没有一个很好的可重复的例子:也许在你的第一次运行中,你只有一个元素在你的向量(它是如何填充的?),并调用未定义的行为,因为你没有检查itg_SPP.scenarios->getVector().end()
  • 或者Z_UB->set不像你想的那样。它是一个多态类吗?set是虚拟的吗?->操作符是否重载?
  • 你的应用程序是多线程的,另一个线程正在改变你的容器?

如果g_SPP全局变量,则其上的迭代器将被任何改变操作无效。


更新—这来自1998年ISO/ANSI规范:

如果需要赋值,则使指向序列元素的所有引用、迭代器和指针失效。如果当前的capacity()小于目标向量的大小,则需要分配。

  • void reserve(size_type n)
  • iterator insert(iterator position, const T& x)
  • void insert(iterator position, size_type n, const T& x)
  • void insert(iterator position, InputIterator first, InputIterator last)

Erasure使指向初始被擦除元素位置之后元素的所有引用、迭代器和指针失效。

  • iterator erase(iterator position)
  • iterator erase(iterator first, iterator second)

调整vector的大小相当于调用inserterase。根据23.2.4.2/6:resize(sz, c=value_type())具有与:

相同的效果
if (sz > size())
    insert(end(), sz - size(), c);
else if (sz < size())
    erase(begin() + sz, end());
else
    ;

a std::vector<T>::iterator将无效,如果你在迭代它的同时添加或删除元素,如果向量需要在内部调整自己的大小,当添加一个元素。

. getvector()返回vector的副本。将迭代器与完全不同对象的迭代器的结束点进行比较是没有意义的。返回一个引用解决了这个问题。

@Xeo还指出了一个更好的解释:当从这样的副本创建迭代器时:

std::vector< std::string >::iterator it = g_SPP.scenarios->getVector().begin();

副本立即销毁,从而使刚刚创建的迭代器失效。所以迭代器一开始就不应该返回第一个元素,但我只能猜测这是隐藏在编译器的实现中。