Какой оператор удаления?

Есть ли разница между:

operator delete(some_pointer);

и

delete some_pointer;

, и если да, то в чем разница, и где следует использовать один и где другой вариант этого оператора? Спасибо.

14
задан There is nothing we can do 27 August 2010 в 18:56
поделиться

4 ответа

По иронии судьбы, оператор delete и оператор delete() — это не одно и то же.

delete some_pointer; вызывает деструктор объекта, на который указывает some_pointer, а затем вызывает оператор delete() для освобождения памяти.

Обычно вы не вызываете operator delete() напрямую, потому что если вы это сделаете, деструктор объекта не будет вызван, и вы, вероятно, столкнетесь с утечкой памяти.

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

В довершение всего, вы также должны знать, что удалить и удалить [] — это две разные вещи.

22
ответ дан 1 December 2019 в 08:41
поделиться

оператор delete() просто освобождает память. delete some_pointer вызывает деструктор some_pointer, а затем вызывает оператор delete().

6
ответ дан 1 December 2019 в 08:41
поделиться

delete some_pointer; является «правильным» для использования.

operator delete(some_Pointer); существуют в основном как артефакт синтаксиса для определения собственного оператора удаления. То есть, поскольку вы определяете оператор «плюс» как

 myclass::operator+(myclass b) {....}

, вы действительно можете написать:

 myclass c = a.operator+(b);

, но никто никогда этого не делает. Они используют:

 myclass c = a + b;

Точно так же можно написать operator delete(some_Pointer);, но никто этого не делает.

2
ответ дан 1 December 2019 в 08:41
поделиться

По крайней мере, по моему опыту, чаще реализуют оператор new и operator delete, чем реально их использовать (т.е. вызывать) хотя бы напрямую.

Обычно вы используете оператор new и оператор delete косвенно — вы пишете новое выражение, например A *a = new A; . Чтобы реализовать это, компилятор генерирует код, который вызывает оператор new для выделения необработанной памяти, а затем вызывает A::A для преобразования этой необработанной памяти в A. объект, как если бы вы написали:

void *temp = operator new(sizeof A);  // allocate raw memory with operator new
A *a = new(temp) A;                   // convert raw memory to object with placement new

Когда вы закончите с объектом, вы используете delete A;. Чтобы реализовать это, компилятор вызывает dtor для объекта, а затем освобождает память примерно так, как вы сделали:

a->~A();
operator delete(a);

Существуют также operator [] new и operator [] delete , которые используются, когда/если вы выделяете/удаляете массивы — но не обязательно есть какая-то реальная разница между обычной версией и версией массива — они обе просто выделяют указанный объем необработанной памяти (хотя вы может предположить, что версии массива будут выделять относительно большие объемы памяти, и на этой основе выполнить некоторую оптимизацию).

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

Один интересный момент: оператор new, оператор [] new, оператор delete и оператор []deleteвсегдастатические члены класса, даже если вы явно не включаетеstatic` в их объявление/определение.

Также существуют глобальные версии всех четырех (::operator new, ::operator [] new, ::operator delete и ::оператор [] delete). Они отмечают «границу» между «внутренним» управлением памятью C++ и внешним миром. Обычно они выделяют относительно большие участки памяти из операционной системы, а затем возвращают меньшие участки остальной части программы по запросу. Если вы хотите (попытаться) оптимизировать управление памятью для всей вашей программы, вы обычно делаете это, перегружая (или, на самом деле, заменяя) их. Опять же, типичной причиной может быть то, что вы планируете разместить множество мелких объектов (но не только в нескольких классах). Одним из примеров этого является библиотека Boost Pool.

Прямое использование любого из вышеперечисленных обычно ограничивается ситуациями, когда вам нужен блок необработанной памяти, а не объектов. Одним из примеров может быть реализация ваших собственных классов контейнеров.Например, std::vector обычно использует ::operator new (через объект Allocator) для выделения памяти для хранения объектов. Поскольку он должен иметь возможность выделять хранилище, но только позже (или, возможно, никогда) создавать объекты в этом хранилище, он не может просто использовать что-то вроде data = new T[size]; — он чтобы выделить необработанную память, затем используйте новое размещение для создания объектов в памяти по мере их добавления в коллекцию (например, когда вы отправляете назад объект). То же самое верно и для std::deque. Если вы хотите (например) реализовать свой собственный кольцевой буфер «с нуля», обрабатывая все управление памятью напрямую, вместо того, чтобы использовать что-то вроде vector для хранения, вам, вероятно, понадобится/хотите сделать то же.

2
ответ дан 1 December 2019 в 08:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: