Reputation: 149
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;
Upvotes: 5
Views: 6128
Reputation: 153919
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 (e.g. 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).
Upvotes: 0
Reputation: 126
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 - e.g. 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.
Upvotes: 0
Reputation: 9097
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.
Upvotes: 2
Reputation: 7225
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.
Upvotes: 2