У меня проблема с 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(...){
...
}
}
Может кто-нибудь сказать мне, как это решить?
ПРИМЕЧАНИЕ: я не могу определить шаги, чтобы воспроизвести его.
THX заранее!
Добавление деталей об объекте & карта:
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;
Очевидно, что операция std :: map вызывает проблему
m_waitingQueue[newObj->uid] = *newObj;
На самом деле это операция вставки карты, которая могла бы выделить память за сценой: Как распределяется карта STL? Стек или куча?.Одна из возможных причин — выделение памяти для исключения неправильного размещения: Недопустимые исключения размещения в C ++.
Но этот код сам по себе не приводит к объяснению того, что происходит за кулисами. Я думаю, что требуется больше информации, связанной с m_waitingQueue, поскольку переменная является глобальной, что может быть сделано вне этой функции.
исключение std::bad_alloc
средства «operator new
не удалось «. Так что либо operator new
вызывается operator*
на 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[]
, Если фиктивное распределение не завершится неудачно, вы можете с уверенностью сказать, что в конструкторе копирования есть ошибка.
возможно Add2WaitList(Object<LPVOID>)
просто звонят миллионы раз, пока у тебя не кончится память.
В этом случае причина будет лежать в другом месте кода — например, в форме бесконечного цикла или регрессии. Другой возможной причиной будет, если ваш Object
по неосторожности все становятся разными uid
s. Это может произойти, когда uid
например, получается из неинициализированного числа.
operator new()
функция не может найти запрошенный
объем памяти. Эта функция может быть вызвана из new
выражение или
непосредственно в распределителе std::map
,
Вы не даете никакой информации относительно контекста.
реальный вопрос: всегда ли это терпит неудачу в этой конкретной точке.
Если у вас действительно не хватает памяти (например, из-за
утечка памяти), можно было бы ожидать, что он ударит другие распределения как
Что ж. Другие возможности в том, что вы портите свободный
космическая арена непосредственно перед вызовом этой функции, или что есть
проблема с конструктором копирования Object<LPVOID>
который
заставляет его запрашивать неограниченную память, или который портит
Арена свободного пространства, так что следующее распределение не удается. Вы
скопировать этот объект в другом месте? Тот факт, что вы проходите мимо
указатель подсказывает, может быть, нет, в этом случае это будет
место, где вы увидите проблему.
РЕДАКТИРОВАТЬ:
Поскольку вы разместили код для Object
: где делать Object
вы используете оригинал? И на что обычно указывают указатели,
и если он распределяется динамически, как управляется удаление?
Так как Object
имеет нет определяемые пользователем конструкторы, что означает
что будут случаи, когда указатели содержат случайный мусор.
И удаление случайных указателей является очень хорошим способом повредить
свободное пространство арены.
Также: я замечаю, что у вас есть то, что выглядит как синхронизация
примитивы (Lock()
а также Unlock()
). Где еще
m_waitingQueue
используемый? Если m_waitingQueue
можно получить доступ из
другой поток, все доступы к m_waitingQueue
должно быть
синхронизируется, используя тот же объект синхронизации
(m_syncWQ
). Попытка изменить m_waitingQueue
в другой
нить в то время как вы изменяете его здесь также может привести к
неопределенное поведение (где-то объект очереди пишет
где это не должно).