2013-03-20 2 views
4

Ищу реализовать (дважды), связанный список, который только звонки placement new внутренне, направляя всю память в пул, наделенного что-то вроде:Размещение нового с станд :: Список

char *memPool = new char[4096]; // One-off normal 'new' 

Изначально я был собирается реализовать мой собственный класс, который берет указатель на пул выделенных ресурсов (класс управления a). Однако сначала хочу быть уверенным, что я не могу достичь такого же результата с std::list. В частности, меня беспокоит the third section of David Rodríguez's answer to this SO question.

Это имеет смысл, что std::list придется звонить new и delete на его составные узлы, но я хочу, чтобы изменить это поведение так, что все узлы должны быть наделив placement new в мой пользовательский бассейн. Поэтому мой вопрос:

Есть ли способ, чтобы указать, что placement newstd::list, такие как:

std::list<std::shared_ptr<Cls>> myList = new (pool.getFreeAddr()) list<Cls>; 

следует также выделить свои узлы с помощью пользовательского аллокатора, так что всего хранятся строго внутри мои пул памяти?

(Примечание: Я отдаю себе отчет в необходимости использования функций пользовательского выделения/удаления, с shared_ptrs, если я хочу их в бассейне пользовательских памяти тоже.)

ответ

5

Вы должны:

  • Напишите шаблон класса MyAllocator, который удовлетворяет требованиям Allocator ([allocator.requirements] в стандарте).
  • Используйте std::list<T, MyAllocator<T> > вместо std::list<T>.

Если вам нужен тип вашего списка, чтобы быть специально std::list<T> (например, потому что вы хотите, чтобы вызывать функции, которые принимают std::list<T> & и чей интерфейс вы не можете изменить), то вам не повезло, потому что Тип распределителя является частью типа контейнера.

Будьте осторожны с требованиями распределителя, они странные. В частности, вам понадобится rebind для list, и это немного сложно.

Кроме того, в C++ 03 нет никакой гарантии, что Распределитель экземпляров уважают, только распределители типа, что фактически означает, что указатель на бассейн вы выделяя из потребностей, которые будут сохранен со статическим а не как переменная экземпляра. Я думаю, что это было изменено на C++ 11, но я могу ошибаться. Это действительно имеет значение, если вы хотите использовать несколько разных пулов в своей программе.

+0

** Написание ** 'rebind' тривиально. Логика, стоящая за ней, сложна. –

+0

@PeteBecker: хороший пункт. Но это означает, что, например, ваш распределитель не может предположить (возможно, как оптимизацию), что он будет использоваться только с типом 'T', который вы указываете в контейнере. Полагаю, мне не нужно упоминать об уловке - этот факт должен быть очевидным в любом случае, учитывая, что он используется связанным списком, а «rebind» - это всего лишь механизм. –

+1

Нет, это следует упомянуть; это просто, что хитрость заключается в том, что он делает **, а не в том, чтобы писать на самом деле. –