C ++ размещение нового против перегрузки нового - PullRequest
6 голосов
/ 09 января 2011

Многие вопросы на SO задают вопрос о размещении новой функции C ++ ( пример 1 , пример 2 ), для чего она используется. Многие ответы говорят - пользовательское размещение объектов, как в заранее выделенных местах.

Но вопрос в том, зачем нужно новое размещение для этого? Не достаточно ли просто перегрузить оператор, новый для класса? С помощью оператора перегрузки, нового для класса, я могу точно контролировать, откуда берется память - например, пользовательский распределитель вызовов. Так зачем мне новое размещение для этой цели?

Ответы [ 4 ]

8 голосов
/ 09 января 2011

Placement New

Лучший пример - подумать о std :: vector

Как std :: vector помещает новые элементы в массив?

Когда вы добавляетеНовый элемент в конце вектора должен использовать размещение new.

class MyVector
{
    char*  data;
    size_t size;

    MyVector() : size(0), data(new char[1000]) {}

    // Placement new copy construction of element into array.
    void push_back(T const& t) { new (data + (sizeof(T) * size)) T(t); ++size;}
};

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

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

Перегрузка новой

Перегрузка новой позволяет контролировать пространство, используемое, когда объект имеет dynamic storage duration.Возможно, ваши ожидаемые шаблоны использования не подпадают под обычные шаблоны использования, и вы хотите оптимизировать создание / уничтожение.Возможно, вы хотите создать собственную сборку мусора (для определенного типа).

Основное отличие состоит в следующем:

  • Перегрузка новых элементов управления созданием пространства для «динамического хранилища»объекты длительности.
  • Размещение можно использовать как для динамических, так и для автоматических объектов продолжительности хранения (я полагаю, также статических).И используется внешне для управления объектами.

Обзор:

Оба являются угловыми случаями для языка и редко используются в обычном коде (я думаю, что я написал 2 новых перегрузки и один класскоторый использует размещение новых (для реального производственного кода / не включает эксперименты и тестирование) в течение 15 лет).

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

6 голосов
/ 09 января 2011

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

Ответ Мартина Йорка является прекрасным примером в этом отношении: std::vector<> придерживается своей собственной стратегии распределения без добавления каких-либо требований к типу T.

0 голосов
/ 09 января 2011

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

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

Но я все равно не вижу, как оператор new может работать в качестве замены «размещения нового». : -)

Кроме того, поскольку у предмета этого вопроса есть ключевое слово «версус», я считаю, что это понятие сравнения между размещением new и оператором new. С этим пониманием, пожалуйста, обратите внимание, что объект, размещенный посредством размещения new, требует другой стратегии его «разрушения»: нужно вызвать вызов деструктора для этого объекта вручную. (это единственный случай в языке, когда программисту приходится вызывать деструктор вручную). В случае перегруженного оператора new будет вызвано перегруженное удаление, если оно предоставлено программистом. Они не обязаны здесь вызывать деструктор вручную: простой ¨delete obj; ¨ поможет.

Извините за подробный ответ, но я надеюсь, вы поняли суть.

0 голосов
/ 09 января 2011

В пользовательских распределителях вам будет лучше использовать новое размещение для управления одним большим предварительно выделенным буфером по вашему выбору из-за производительности.Стандартная реализация кучи ужасно медленная, и если вы выделяете / освобождаете много объектов одинакового размера, пользовательская реализация может быть в 1000 раз быстрее (без преувеличения)

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

Пользовательская реализация с размещением new может быть намного быстрее, если вы знаете, что все выделенные блоки будут, например, одинакового размера.

...