5

我正面临 std::map 的问题。由于未知原因,有时插入映射会导致“错误分配”异常。

以下是我用于插入地图的功能。

BOOL Add2WaitList(Object<LPVOID> *newObj)
{
    try
    {
        _set_se_translator( trans_func );
        m_syncWQ.Lock();
        if (m_waitingQueue.count(newObj->uid)>0)
        {
            m_syncWQ.Unlock();
            return FALSE;
        }
        m_waitingQueue[newObj->uid] = *newObj; <-- failing here
        m_syncWQ.Unlock();
        return TRUE;
    }
    catch(std::exception &ex){
        ...
    }
    catch(SE_Exception &e){
        ...
    }
    catch(...){
        ...
    }
}

有人可以告诉我如何解决这个问题吗?

注意:我无法确定重现它的步骤。

提前谢谢!

添加有关对象和地图的详细信息:

template <typename T>
struct Object{
public:
    void Kill()
    {
        if (response!=NULL)
            delete response;
        if (object!=NULL)
            delete object;
    }

    enum objType;
    std::string uid;
    enum status;
    double p;
    enum execType;
    T object;
    LPVOID response;
};

std::map<std::string,Object<LPVOID>> m_waitingQueue;
4

4 回答 4

2

异常std::bad_alloc意味着“operator new失败”。因此,要么operator newoperator*on newObj(我们对此一无所知)调用,要么被映射的插入运算符调用(这极有可能)。

具体来说,当您operator[]使用某些参数 k 在地图上调用时

如果 k 不匹配容器中任何元素的键,则该函数使用该键插入一个新元素并返回对其映射值的引用。请注意,这总是将容器大小增加一,即使没有为元素分配映射值(该元素是使用其默认构造函数构造的)。

(如此处所述)。

Map::operator[]为故障提供强有力的保证:

Strong guarantee: if an exception is thrown, there are no changes in the container.

但不保证不抛出异常(即它不提供不抛出保证)。

operator new引发异常的原因可能具有不同的性质。然而,这一切都归结为:

throws bad_alloc if it fails to allocate storage.

也就是说,正如 JamesKanze 在评论中建议的那样:

std::bad_alloc 的另一个可能原因是未定义的行为。例如,如果他破坏了自由空间竞技场。实际上,如果他真的内存不足,失败的分配会有所不同。如果系统地在这里,我会怀疑 Object 的复制构造函数存在问题,而不是其他任何事情。

这意味着operator new由于程序其他部分的一些错误而无法分配存储。您可以通过在调用operator[]. 如果虚拟分配没有失败,您可以自信地说复制构造函数存在错误。

于 2013-07-19T08:08:32.273 回答
2

很明显,std::map 操作导致了问题

m_waitingQueue[newObj->uid] = *newObj;

它实际上是一个地图插入操作,它可能会在后台分配内存:STL 地图是如何分配的?堆栈还是堆?一个可能的原因是分配内存导致错误分配异常:C++ 中的错误分配异常

但是这段代码本身并不能解释幕后发生的事情。我认为需要更多与“m_waitingQueue”相关的信息,因为该变量是全局变量,可以在此函数之外执行任何操作。

于 2013-07-19T08:26:19.707 回答
0

也许Add2WaitList(Object<LPVOID>)只是被调用了数百万次,直到内存不足。

在这种情况下,原因可能在代码的其他地方——例如以无限循环或回归的形式。另一个可能的原因是,如果您Object的 s 不经意间都得到了不同uid的 s。uid例如,当从未初始化的数字派生时,可能会发生这种情况。

于 2013-07-19T08:59:10.680 回答
0

operator new()函数无法找到请求的内存。该函数可以从new表达式中调用,也可以直接在 的分配器中调用std::map

您没有提供有关上下文的任何信息。真正的问题是:它是否总是在这个特定的点上失败。如果您真的内存不足(例如由于内存泄漏),人们会期望它也会影响其他分配。其他可能性是您在调用此函数之前破坏了可用空间区域,或者复制构造函数存在问题Object<LPVOID>导致它请求无限内存,或者破坏了可用空间区域,因此下一次分配失败. 您是否将此对象复制到其他地方?您通过指针传递它的事实表明可能不是,在这种情况下,这将是您看到问题的地方。

编辑:

既然您已经发布了代码ObjectObject 您使用的来源是哪里?指针通常指向什么,如果是动态分配的,删除是如何管理的?

因为Object没有用户定义的构造函数,这意味着会有指针包含随机垃圾的情况删除随机指针是破坏可用空间领域的一种非常好的方法。

另外:我注意到你有看起来像同步原语(Lock()Unlock())的东西。还用在什么地方 m_waitingQueue?如果m_waitingQueue可以从不同的线程访问,则m_waitingQueue必须使用相同的同步对象 ( m_syncWQ) 同步所有访问。在此处修改另一个线程时尝试m_waitingQueue在另一个线程中进行修改也可能导致未定义的行为(队列对象写入不应该写入的地方)。

于 2013-07-19T08:23:36.543 回答