2011-12-21 2 views
1

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

{ 
    MemoryArena m; 
    std::string* ptr = m.Allocate<std::string>(); 
    // use ptr whatever 
    // Cleaned up when pool is destroyed 
} 

Но это довольно неприятно, когда оно используется несколько раз. Если внутреннее выделение очищено, то оно может быть использовано впоследствии - не плохое предположение, так как определение пула никогда не удаляет объекты до тех пор, пока не закончится его жизнь. рассмотреть следующие вопросы:

struct X { 
    X(MemoryArena* ptr, std::string*& ref) { 
     ref = ptr->Allocate<std::string>(); 
     throw std::runtime_error("hai"); 
    } 
}; 
MemoryArena m; 
std::string* ptr; 
m.Allocate<X>(&m, ptr); 
// ptr is invalid- even though it came from the arena 
// which hasn't yet been destroyed 

Но если внутреннее распределение не очистки, внешнее распределение также не может быть очищены, потому что арена памяти распределяет их линейно, как на аппаратный стеке, поэтому я утечка памяти , Поэтому либо я нарушаю свою семантику, уничтожая объект раньше, либо я утечка памяти.

Любые предложения по устранению этой проблемы?

+2

Что такое 'MemoryArena'? Как мы можем говорить что-либо, не зная об этом? – Nawaz

+0

Непонятно, как вы просачиваете память, когда она освободится, когда арена освободится. – zvrba

+0

@zvrba: выделено, но непригодно, потому что объект никогда не строился, и указатель не возвращался, поэтому память просачивается до тех пор, пока область не будет уничтожена. – Puppy

ответ

2

Возможно, это только пример кода, к которому это относится, но я не думаю, что пользователь должен предположить, что ptr действителен, когда конструктор X выбрасывает. Он также может быть брошен до того, как будет назначен ref.

Так что я бы сказал, очистить внутренний объект, если вы можете (то есть, если передняя часть арены лежит в конце внутреннего объекта). ОК, выделение с арены становится недействительным, что ненормально, но это распределение, которое никогда не должно было превращаться в реальный мир.

Возможно, вы могли бы сделать это явным, с понятием «мягкого» распределения. Не гарантируется, что он будет жить вечно, потому что, хотя он все еще «мягкий», его можно вернуть на арену. Тогда конструктор Х будет делать что-то вроде:

SoftPtr<std::string> tmp(ptr->SoftAllocate<std::string>()); 
stuff_that_might_throw(); 
ref = tmp.release(); 

Выполнение деструктор SoftPtr без без первого вызова release означает, что никакие ссылки на объект не был выставлен. Он вызывает функцию MemoryArena, что делает что-то вроде:

  • разрушится объект
  • проверить, является ли последний выделения из арены
    • если да, вычесть размер от тока арены указатель позиции
    • если нет, то ничего не делать (память утекает)

Таким образом, любое количество выделений может быть «отменено», если оно выполнено в обратном порядке.

+0

Отличные рекомендации. Я, вероятно, позволю указателю стать недействительным. – Puppy

0

По самой семантике пулов памяти, и, как вы заявили о себе в этом вопросе, можно освободить только пул в целом, а не отдельные объекты. Но вы хотите сделать именно это.

Возможность оснастить распределитель brk-like functions, чтобы получить и установить следующий адрес распределения.Это дает вам механизм низкого уровня, который вы можете использовать, чтобы построить все, что захотите, поверх него.