2016-11-21 8 views
7

У меня есть класс Item, который определяет свой собственный оператор новый и оператор удалить следующим образом:Является ли деструктор неявным в функции перегруженного оператора delete?

class Item 
{ 
public: 
    Item(const std::string &s):msg(s) 
    { 
     std::cout<<"Ctor: "<<msg<<std::endl; 
    } 
    static void* operator new(size_t size, int ID, const std::string &extra) 
    { 
     std::cout<<"My Operator New. ID/extra: "<<ID<<"/"<<extra<<std::endl; 
     return ::operator new(size); 
    } 
    static void operator delete(void* p) 
    { 
     std::cout<<"My Operator Delete"<<std::endl; 
     return; 
    } 
    ~Item() 
    { 
     std::cout<<"Destructor: "<<msg<<std::endl; 
    } 
    void Print() 
    { 
     std::cout<<"Item::msg: "<<msg<<std::endl; 
    } 
private: 
    std::string msg; 
}; 

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

int main() 
{ 
    Item *pI=new(1,"haha")Item("AC Milan"); 
    std::cout<<"before delete"<<std::endl; 
    delete pI; 
    std::cout<<"after delete"<<std::endl; 
    return 0; 
} 

выход:

My Operator New. ID/extra: 1/haha 
Ctor: AC Milan 
before delete 
Destructor: AC Milan 
My Operator Delete 
after delete 

Как вы можете видеть, delete pI называет свою собственную функцию удаления, в котором nothi ng выполняется за исключением вывода журнала. Однако из результата деструктор Item вызывается в delete pI, который не вызывается в моей собственной функции удаления.

Итак, в этом случае деструктор будет называться неявным образом в перегруженной функции удаления?

+0

Я использую g ++ 4.9.3 –

+0

Это то же самое для ваших 'новых' и ваших' delete' операторов. Вы также не вызываете конструктор в свой перегруженный оператор 'new', и он все еще вызывается. Конструкторы и деструкторы всегда вызывается при использовании операторов 'new' и' delete'. –

+2

Распределение памяти и создание/разрушение объекта - две разные вещи. Перегрузка функций распределения влияет только на первое; последний полностью контролируется основными языковыми правилами. –

ответ

4

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

Да. Для delete expression, (1) деструктор будет вызываться сначала, тогда (2) будет вызван apporeate operator delete; поиск имен и разрешение перегрузки будут выполняться на этом этапе.

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

После этого, если соответствие нового выражение не было объединено с другой новой экспрессией (так как C++ 14) удаление выражения вызывает функцию Deallocation, либо operator delete (для первой версии выражения) или operator delete[] (для вторая версия выражения).

0

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

Деструкторы и перегруженные операторы удаления взаимодействуют сложным образом. Когда вы говорите

delete pI; 

это на самом деле компилирует к вызову вашего деструктора, и никаких ссылок не делается «удалить».

Ваш деструктор имеет (GCC) два экземпляра в VTable (если виртуальный) или (MSVC) логический аргумент. Экземпляры/bool используются для определения того, должен ли скомпилированный деструктор быть удалением или вызовом деструктора без удаления. Как вы можете догадаться, удаление деструктора затем отвечает за вызов оператора связи для удаления ссылки. Если бы вы написали

pI->~Item(); 

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

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

+0

Для полноты, есть третий деструктор, который используется для разрушения вашего класса, но не для ваших виртуальных баз. Это не актуально в этом обсуждении, поскольку у вас нет виртуальных баз. – dascandy

1

Деструктор не вызывается перегруженной функцией operator delete().

Однако delete выражение (в вашем случае, delete pI) имеет эффект первого вызова деструктора для объекта, а затем вызывает соответствующую перегрузку operator delete().