【问题标题】:Problem with deque: map<..., deque<> > fails, but vector and list aren't?deque 的问题:map<..., deque<>> 失败,但 vector 和 list 不是?
【发布时间】:2011-08-31 12:03:22
【问题描述】:

我有一个代码:

typedef map<Coordinate3D, deque<someClass > > someMap;
someMap *newEM;
someMap::iterator iter;
//...
(*newEM)[iter->first].insert((*newEM)[iter->first].end(),
                             iter->second.begin(), iter->second.end());

打算合并两个someMap。但是由于内存错误(0xcdcdcdcd指针)导致程序崩溃的问题。只有当 map 包含双端队列时才会发生这种情况,并且当有列表或向量时一切正常。可能是什么?

这是我使用双端队列时的内存问题。 Insert 调用了一堆复制构造函数。 我还有someClass 的一些属性,在将点复制到内存后,看起来像这样:

0x00959B48 00 00 00 00 00 00 00 00

就在错误发生之前(在someClass 的复制构造函数中),该字段(复制对象)指向此处(相同地址):

0x00959B48 f0 9b 95 00 00 00 00 00

这里不远处有一个看起来像地址的东西(0x00959B48):

0x00959B0F fd ab ab ab ab ab

指向该复制对象的其他指针也指向无效内存(0xcdcdcdcd

然后我为那个地址(0x00959B48)设置内存写断点,这就是我发现的:

 msvcr100d.dll!memset...//breakpoint activated here
 msvcr100d.dll!_free_dbg_nolock...
 msvcr100d.dll!_free_dbg...
 msvcr100d.dll!operator delete...
 program.exe!someClass::~someClass()  Line 294 + 0x21 bytes C++
 program.exe!std::swap...
 program.exe!std::iter_swap...
 program.exe!std::_Reverse...
 program.exe!std::reverse...
 program.exe!std::deque<...>::_Insert...
 program.exe!std::deque<...>::insert...

所以我们所拥有的是销毁该对象。

 msvcr100d.dll!memset...
 msvcr100d.dll!_heap_alloc_dbg_impl...
 msvcr100d.dll!_nh_malloc_dbg_impl...
 msvcr100d.dll!_nh_malloc_dbg...
 msvcr100d.dll!operator new...
 program.exe!std::_Allocate<std::_Container_proxy>...
 program.exe!std::allocator<std::_Container_proxy>::allocate...
 program.exe!std::_Deque_val...
 program.exe!std::deque<..>::deque<..> >()
 program.exe!std::map<...::operator[]

等值在 STL 代码中多次更改如下:

if (_Right._Myproxy != 0)//<--breaks here
        _Right._Myproxy->_Mycont = (_Container_base12 *)&_Right;

进入这个

0x00959B48 08 f6 12 00 00 00 00 00

最后回到我们最后所拥有的

0x00959B48 f0 9b 95 00 00 00 00 00

所以我们所拥有的是对象被销毁,内存被覆盖,并且对象回到充满垃圾(可能是地图数据)的同一个内存。 我用 list 和 vector 替换了 deque ,两者都运行良好。 所以有一个问题:deque到底发生了什么,或者我做错了,我应该如何解决这个问题?

编辑:这是功能代码:

void MergeEffectsMaps(EffectsMap **dest, EffectsMap *src) {
    EffectsMap *newEM = *dest;
    EffectsMap::iterator findIter;
    for (EffectsMap::iterator iter = src->begin();
            iter != src->end(); iter++) {
        findIter = newEM->find(iter->first);
        if (findIter != newEM->end()) {//exists
            if (!iter->second.empty())
                findIter->second.insert(findIter->second.end(),
                    iter->second.begin(), iter->second.end());
        } else {
            if (!iter->second.empty()){
                (*newEM)[iter->first];
                (*newEM)[iter->first].insert((*newEM)[iter->first].end(),
                    iter->second.begin(), iter->second.end());//<----problem
                }
        }
    }
}

这是一些类:

class someClass {
public:
    complexClass1 *value1;
    complexClass2 *value2;
    float value3;
    int value4;
    someClass(){
     value1=new complexClass1 ();
     value2=new complexClass2 ();
     value3=0;
     value4=0;
    };
    someClass(const FieldEffect& cp_val){
     value1=new complexClass1 (*cp_val.value1);//copy-constructor
     value2=new complexClass2 (*cp_val.value2);
     value3=cp_val.value3;
     value4=cp_val.value4;
    };
    ~someClass(){
     delete value1;
     delete value2;
    };
};

【问题讨论】:

  • 只有1个迭代器的情况下,原代码如何合并2个map?
  • someMap *newEM; new'ed this,对吧?
  • 是的,当然还有第二个迭代器。
  • newEM 我初始化为指向使用 ** 传递给函数的现有映射的指针。这是代码pastebin.com/3BVWPPVT
  • Youtch,这些指针是怎么回事? C++ 有 references,这些对于这种情况非常有用...

标签: c++ stl deque


【解决方案1】:

我认为您使用 insert 使迭代器无效。对于大多数容器,您必须在每次插入后重新设置迭代器值,即:

it = container.insert (it, element);

而不仅仅是:

container.insert (it, element);  // it may not be valid anymore

【讨论】:

  • 我又看了一遍,没有什么可以失效的(编辑后的帖子),只有一个迭代器可能受到影响-iter,但我只是用它来读取来自@987654325的数据@map,另一个迭代器finIter只用了一次,用于检测其他map中是否存在这样的key值。
【解决方案2】:

您在someClass 中定义了一个复制构造函数,但没有赋值运算符。

一旦对象发生“有趣”的事情,您将泄漏旧值,然后有两个对象指向同一个complexClass。当其中第一个删除其指针时,所有副本都将具有无效指针!

尝试复制这些无效对象之一会破坏您所看到的方式。

【讨论】:

  • 谢谢,有帮助!有些事情让我相信我应该只定义复制构造函数:The container may copy elements using a copy constructor or an assignment;
  • @Grumm -- 见Rule of Three
猜你喜欢
  • 2020-10-01
  • 2015-01-15
  • 2012-03-07
  • 2023-03-14
  • 1970-01-01
  • 2015-05-19
  • 2017-06-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多