C++迭代器随机失效

发布于 2024-12-19 19:35:55 字数 1183 浏览 1 评论 0原文

我迷路了: std::string 向量的迭代器可以完美工作,除非在 it++ 之前有函数调用 (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() 函数,则访问它将使程序崩溃。关于迭代器,我是否遗漏了一些重要的东西?

I'm lost: An iterator of a vector of std::string works perfectly unless there is a function call (Z_UB->set() ) before it++. Here's the code:

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;

creates the following output

begin of vector: scn1

However, if I move the function call like this:

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);

The result is the following, which is the expected behaviour:

begin of vector: scn1
second of vector: scn2

Inside the Z_UB->set() function there is nothing left but the call itself:

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;
}

So if I call the Z_UB->set() function after I created the iterator, accessing it will crash the program. Is there anything vital that I missed about Iterators?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

耶耶耶 2024-12-26 19:35:55

几种可能性:

  • 要么你没有一个好的可重现的例子:也许在你的第一次运行中你的向量中只有一个元素(它是如何填充的?),并且调用了未定义的行为,因为你没有检查它 反对 g_SPP.scenarios->getVector().end()
  • Z_UB->set 不会按照你的想法做。它是一个多态类吗? set 是虚拟的吗? -> 运算符是否重载?
  • 您的应用程序是多线程的,并且另一个线程正在改变您的容器吗?

Several possibilities:

  • Either you do not have a good reproductible example: maybe in your first run you had only one element in your vector (how is it filled?), and invoked undefined behaviour because you did not check it against g_SPP.scenarios->getVector().end()
  • Or Z_UB->set does not do what you think. Is it a polymorphic class? Is set virtual? Is the -> operator overloaded?
  • Is your app multithreaded and another thread is mutating your container?
风柔一江水 2024-12-26 19:35:55

如果g_SPP是一个全局变量,那么任何变异操作都会使其上的迭代器失效。


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

如果需要分配,以下内容会使引用序列元素的所有引用、迭代器和指针无效。如果当前capacity()小于目标向量大小,则需要进行分配。

  • void Reserve(size_type n)
  • 迭代器插入(迭代器位置,const T& x),
  • void insert(迭代器位置,size_type n, const T& x)< /code>、
  • void insert(iteratorposition,InputIteratorfirst、InputIteratorlast)

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

  • 迭代器擦除(迭代器位置)
  • 迭代器擦除(迭代器第一个,迭代器第二个)

调整向量大小相当于调用 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
    ;

If g_SPP is a global variable then iterators over it will be invalidated by any mutating operation.


Update -- this is from the 1998 ISO/ANSI spec:

The following invalidate all references, iterators, and pointers referring to elements of the sequence if an allocation is required. An allocation is required if the current capacity() is less than the target vector size.

  • 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), and

Erasure invalidates all references, iterators, and pointers referring to elements after the position of the initial erased element.

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

Resizing a vector is equivalent to calling either insert or erase. According to 23.2.4.2/6: resize(sz, c=value_type()) has the same effect as:

if (sz > size())
    insert(end(), sz - size(), c);
else if (sz < size())
    erase(begin() + sz, end());
else
    ;
や莫失莫忘 2024-12-26 19:35:55

如果在迭代时添加或删除元素,或者在添加元素时向量需要在内部调整自身大小,则 std::vector::iterator 将会失效。

a std::vector<T>::iterator will be invalidated if you add or remove elements while iterating over it, if the vector needs to resize itself internally, when an element is added.

青柠芒果 2024-12-26 19:35:55

.getVector() 返回向量的副本。将迭代器与完全不同对象的迭代器的终点进行比较是没有意义的。返回参考解决了这个问题。

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

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

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

.getVector() returned a copy of the vector. Comparing an iterator to the end point of the iterator of a completely different object doesn't make sense. Returning a reference solved the problem.

@Xeo also pointed out a much better explanation: When creating an iterator from a copy like this:

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

the copy immediately is destroyed thus invalidating the just created iterator. So the iterator shouldn't have returned the first element in the first place, but I can merely guess that this is hidden deeply in the implementation of the compiler.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文