简体   繁体   中英

std::map bad allocation error

I'm facing an issue with std::map. For unknown reasons sometimes insertions to map lead to a "bad allocation" exception.

Below is the function which I use for inserting into the 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(...){
        ...
    }
}

Can someone tell me how to solve this?

NOTE: I cannot identify the steps to reproduce it.

THX in advance!

Adding details about Object & map:

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;

Exception std::bad_alloc means " operator new failed". So either operator new is getting called by operator* on newObj (which we don't know anything about) or by the insertion operator of the map (which is extremely more likely).

Specifically, when you call operator[] on the map with some parameter k

If k does not match the key of any element in the container, the function inserts a new element with that key and returns a reference to its mapped value. Notice that this always increases the container size by one, even if no mapped value is assigned to the element (the element is constructed using its default constructor).

(as documented here ).

Map::operator[] provides the strong guarantee on failure:

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

but doesn't guarantee for an exception not to be thrown (ie it provides no no-throw guarantee).

The reason for operator new throwing an exception could be of different nature. However, it all boils down to:

throws bad_alloc if it fails to allocate storage.

That said, as JamesKanze suggests in the comments:

Another possible reason for std::bad_alloc is undefined behavior. If he's corrupted the free space arena, for example. And realistically, if he's really running out of memory, the allocation where it fails would vary. If it is systematically here, I would suspect a problem in the copy constructor of Object, more than anything else.

meaning that operator new fails to allocate storage because of some bug in other portions of the program. You can debug against his null-assupmtion (as statistician would call it) by means of allocating a (very) big chunck of data right before the call to operator[] . If the dummy allocation doesn't fail you can say that there is a bug on the copy constructor with good confidence.

It is obvious that std::map operation cause the problem

m_waitingQueue[newObj->uid] = *newObj;

It is actually a map insert operation, which would possiblly allocate memory behind the scene: How is a STL map allocated? Stack or Heap? .One possible reason is allocating memory lead to Bad allocation exception : Bad allocation exceptions in C++ .

But this code does not itself lead to explaination what is going on behind the scene. I think more information related to "m_waitingQueue" is needed, since the variable is global, which anything might be done to outside this function.

The operator new() function is unable to find the requested memory. This function may be called from a new expression, or directly, in the allocator of std::map .

You don't give any information with regards to the context. The real question is: is it always failing at this particular point. If you were really running out of memory (eg because of a memory leak), one would expect it to hit other allocations as well. Other possibilities are that you are corrupting the free space arena just before calling this function, or that there is a problem with the copy constructor of Object<LPVOID> which causes it to request unlimited memory, or which corrupts the free space arena, so that the next allocation fails. Do you copy this object elsewhere? The fact that you pass it by pointer suggests maybe not, in which case, this would be the place where you'd see the problem.

EDIT:

Since you've posted the code for Object : where do the Object you use originate? And what do the pointers normally point to, and if it is dynamically allocated, how are the deletes managed?

Because Object has no user defined constructors, which means that there will be cases where the pointers contain random junk. And deleting random pointers is a very good way to corrupt the free space arena.

Also: I notice that you have what looks like synchronization primitives ( Lock() and Unlock() ). Where else is m_waitingQueue used? If m_waitingQueue can be accessed from a different thread, all accesses to m_waitingQueue must be synchronized, using the same synchronization object ( m_syncWQ ). An attempt to modify m_waitingQueue in another thread while you're modifying it here could also lead to undefined behavior (with the queue object writing somewhere where it's not supposed to).

Perhaps Add2WaitList(Object<LPVOID>) is simply being called millions of times until you run out of memory.

In that case, the cause would lie elsewhere in the code - eg in the form of an infinite loop or regression. Another possible cause would be if your Object s inadvertently all get different uid s. This could happen when uid is derived from an uninitialized number, for example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM