Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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;
like image 902
SairuS Avatar asked Oct 03 '22 12:10

SairuS


2 Answers

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.

like image 61
lulyon Avatar answered Oct 11 '22 15:10

lulyon


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 (i.e. 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.

like image 27
Stefano Falasca Avatar answered Oct 11 '22 13:10

Stefano Falasca