【问题标题】:Vector.erase(Iterator) causes bad memory accessVector.erase(Iterator) 导致错误的内存访问
【发布时间】:2011-02-25 23:59:19
【问题描述】:

我正在尝试对存储在 vector 中的 videoObjects 进行 Z-Index 重新排序。计划是识别videoObject,它将放在vector 的第一个位置,将其擦除,然后将其插入第一个位置。不幸的是,erase() 函数总是会导致错误的内存访问。

这是我的代码:

testApp.h:

vector<videoObject> videoObjects;
vector<videoObject>::iterator itVid;

testApp.cpp:

// Get the videoObject which relates to the user event
for(itVid = videoObjects.begin(); itVid != videoObjects.end(); ++itVid) {
  if(videoObjects.at(itVid - videoObjects.begin()).isInside(ofPoint(tcur.getX(), tcur.getY()))) {
   videoObjects.erase(itVid);
  }
}

这应该很简单,但我只是看不出我在哪里走错了路。

【问题讨论】:

  • 为什么是videoObjects.at(itVid - videoObjects.begin()) 而不是(*itVid)
  • 试过了,但会导致以下错误:没有匹配函数调用'std::vector >::at(videoObject&)'
  • 你根本不需要使用at();取消引用迭代器会返回对指向元素的引用。
  • @James:你是对的,谢谢!
  • 对这个问题重复问题...stackoverflow.com/questions/2728551/c-iterators-problem/… - 我们是否关闭了相同解决方案的问题?这是相同的旧擦除无效迭代器问题。

标签: c++ vector erase openframeworks


【解决方案1】:

请注意,从向量中逐个擦除元素具有二次复杂度。 STL 来救援!

#include <algorithm>
#include <functional>

videoObjects.erase(
    std::remove_if(
        std::bind2nd(
            std::mem_fun_ref(&videoObject::isInside),
            ofPoint(tcur.getX(), tcur.getY())
        ),
    ),
    videoObjects.end()
);

【讨论】:

    【解决方案2】:

    你应该这样做

    itVid = videoObjects.erase(itVid);
    

    引用cplusplus.com:

    [vector::erase] 使所有迭代器和对 positionfirst 之后元素的引用无效。

    返回值:一个随机访问迭代器,指向函数调用擦除的最后一个元素之后的元素的新位置,如果操作擦除了序列中的最后一个元素,则该位置是向量结束。

    更新:在条件中访问当前元素的方式看起来很奇怪。还必须避免在erase 之后增加迭代器,因为这会跳过一个元素并可能导致越界错误。试试这个:

    for(itVid = videoObjects.begin(); itVid != videoObjects.end(); ){
      if(itVid->isInside(ofPoint(tcur.getX(), tcur.getY()))){
        itVid = videoObjects.erase(itVid);
      } else {
        ++itVid;
      }
    }
    

    【讨论】:

    • 致任何使用 Visual C++ 2010 的人:您需要禁用迭代器调试才能使其工作(基本上,迭代器调试在这种情况下被彻底破坏):connect.microsoft.com/VisualStudio/feedback/details/557029
    • 我试过:`for(itVid = videoObjects.begin(); itVid != videoObjects.end(); ++itVid){ if(videoObjects.at(itVid - videoObjects.begin( )).isInside(ofPoint(tcur.getX(), tcur.getY()))){ itVid = videoObjects.erase(itVid);休息; } } 但仍然无法访问内存...
    • @Péter:非常感谢您的帮助。不幸的是,我仍然获得了糟糕的内存访问权限:(
    • @xon1c,你试过调试吗?在失败之前循环执行了多少次?是多个元素被擦除,还是第一次擦除失败?
    • @Péter:向量中有 3 个视频对象。所有 3 都显示在屏幕上。通过单击一个,它会被删除。错误的内存访问发生在任何一个中。因此该函数将始终只擦除一个视频对象,但我已经尝试过了,该对象存储在哪个索引位置并不重要。
    【解决方案3】:

    erase 函数返回下一个有效的迭代器。

    您必须创建一个while 循环并执行类似的操作

    iterator = erase(...)
    

    有相应的检查。

    【讨论】:

      【解决方案4】:

      迭代列表时不能删除,因为迭代器无效。您应该使用 Erase 的返回迭代器将其设置为您当前的迭代器。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-14
        • 1970-01-01
        • 1970-01-01
        • 2018-02-24
        • 1970-01-01
        相关资源
        最近更新 更多