Распределитель STL в C ++ против оператора new - PullRequest
21 голосов
/ 12 апреля 2011

Согласно C ++ Primer 4th edition, стр. 755, есть примечание:

Современные программы на C ++ обычно должны использовать класс распределителя выделить память. Это безопаснее и гибче.

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

Может ли кто-нибудь помочь прояснить это утверждение? и дать мне больше примеров? Когда я должен использовать allocator и когда использовать new? Спасибо!

Ответы [ 2 ]

39 голосов
/ 12 апреля 2011

Для общего программирования, да, вы должны использовать new и delete.

Однако, если вы пишете библиотеку, вы не должны!У меня нет вашего учебника, но я предполагаю, что он обсуждает распределители в контексте написания библиотечного кода.

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

Все контейнеры STL принимают необязательный аргумент шаблона распределителя.Затем контейнер будет использовать этот распределитель для нужд своей внутренней памяти.По умолчанию, если вы опустите распределитель, он будет использовать std::allocator, который использует new и delete (в частности, ::operator new(size_t) и ::operator delete(void*)).

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

Пример реализации пользовательского распределителя для использования с STL и объяснение: Повышение производительности с помощью пользовательских распределителей пула для STL

Side Примечание: Подход STL к распределителям неоптимален по нескольким причинам.Я рекомендую прочитать На пути к лучшей модели распределителя для обсуждения некоторых из этих проблем.

1 голос
/ 12 апреля 2011

Два не противоречат друг другу. Распределители - это PolicyPattern или StrategyPattern, используемые адаптерами контейнеров библиотек STL для выделения кусков памяти для использования с объектами.

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

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


Другим ярким примером будет, например, как библиотека Boost реализует интеллектуальные указатели. Поскольку smartpointers очень малы (с небольшими издержками), накладные расходы могут стать бременем. Для реализации имеет смысл определить специализированный распределитель для выполнения распределений, поэтому можно иметь эффективные std :: set <> smartpointers, std :: map <..., smartpointer> и т. Д.

(Теперь я почти уверен, что boost фактически оптимизирует хранилище для большинства интеллектуальных указателей, избегая любых виртуальных сред, поэтому vft, делая класс структурой POD, с только необработанным указателем в качестве хранилища; некоторые из примеров не будут применяться. Но опять же, экстраполируйте на другие виды интеллектуальных указателей (пересчет интеллектуальных указателей, указатели на функции-члены, указатели на функции-члены со ссылкой на экземпляр и т. Д. И т. Д.))

...