boost :: fast_pool_allocator выбрасывает исключение нарушения прав доступа

Хорошо, у меня возникла небольшая проблема с использованием boost::fast_pool_allocator,

Код у меня работает для первых нескольких звонков fast_pool_allocator::allocate(1),
но затем происходит сбой со следующим сообщением:

Необработанное исключение в 0x000000013fd0fe2d в Engine.exe: 0xC00000005:
Место чтения нарушения доступа 0x0000000000ffffff

Стек вызовов:

Engine.exe!boost::simple_segregated_storage<unsigned __int64>::malloc()  Line 104
Engine.exe!boost::pool<boost::default_user_allocator_new_delete>::malloc()  Line 223
Engine.exe!boost::singleton_pool<boost::fast_pool_allocator_tag,128,boost::default_user_allocator_new_delete,boost::details::pool::win32_mutex,32>::malloc()  Line 59
Engine.exe!boost::fast_pool_allocator<EventDataSize,boost::default_user_allocator_new_delete,boost::details::pool::win32_mutex,32>::allocate(const unsigned __int64 n)  Line 229
Engine.exe!IEventData::operator new(unsigned __int64 size)  Line 46
etc...

Рассматриваемая строка повышающего кода, по-видимому, находится там, где механизм хранения распределителей собирается вернуть следующий свободный блок и удаляет его из
список свободных кусков

void * malloc()
{
void * const ret = first;

// Increment the "first" pointer to point to the next chunk
first = nextof(first); // <--- This is the line that is failing.
return ret;
}

Мой код выглядит так:

class EventDataSize
{
private:
U8 dummyField[128];
};

class IEventData
{
public:
void* operator new(size_t size)
{
void* ptr = boost::fast_pool_allocator<EventDataSize>::allocate(1);
if (!ptr)
throw std::bad_alloc();
return ptr;
}

void operator delete(void* ptr)
{
boost::fast_pool_allocator<EventDataSize>::deallocate((EventDataSize*)ptr, 1);
}

// etc...
}

Как вы видите, я пытаюсь использовать это EventDataSize класс как пустышка, так что любой класс, который наследует от IEventData будет выделен тот же размер (например, 128 байт), что позволит распределителю пула работать успешно с наследованием.

Я использую точно такой же шаблон в другом месте для реализации оператора new с другими базовыми классами, и они, похоже, не сталкиваются с той же проблемой.

Любопытно, если я изменю размер массива EventDataSize::dummyField проблема исчезает (или, по крайней мере, она еще не появилась), но мне не нравится такое нестандартное решение … Я хочу знать, почему этот распределитель делает то, что делает, что я делаю неправильно и как я могу это изящно исправить!

0

Решение

Всегда проверяйте, что ваши теории (какими бы они ни были) верны. У вас, кажется, есть теория, что 128 байтов достаточно для любого IEventData, так что вы можете игнорировать размер? Идите и проверьте это:

void* operator new(size_t size)
{
if ( size > sizeof( EventDataSize ) )
{
throw std::runtime_error("crappy idea, pal");
}
void* ptr = boost::fast_pool_allocator<EventDataSize>::allocate(1);
if (!ptr)
throw std::bad_alloc();
return ptr;
}

Для меня вполне вероятно, что есть данные о событиях размером более 128 байт, и поэтому он запутывает вещи в пуле распределителя пулов.

2

Другие решения

Я понял, потому что у меня был другой базовый класс IControl, использующий тот же шаблон и использующий свой собственный фиктивный элемент ControlSize (также размером 128 байт), что оба fast_pool_allocators использовали один и тот же объект пула под капотом.

Однако один из моих подклассов IControl был больше 128 байт. Поэтому он получал распределение без проблем, но затем перезаписывал связанный список пулов свободных блоков.

По сути, это была именно та проблема, о которой говорил Оо Тииб, но она перешла к немного другому разделу кода.

Я исправил код в обоих местах, как показал Oo Tiib и bish-bash-bosh, он работает как шарм!

3