Оператор new () ведет себя по-разному, когда оператор delete () удаляется в зависимости от существования конструктора по умолчанию - PullRequest
17 голосов
/ 12 февраля 2020

Создание нового объекта класса C с оператором new () выдает здесь ошибку:

class C
{
public:
    C() {}
    virtual ~C() {}

    void operator delete(void*) = delete;
};


int main()
{
    C* c = new C;
}

с C2280: 'void C::operator delete(void *)': function was explicitly deleted

Но когда я заменяю C() {} на C() = default; или удалите строку, чтобы компилятор вставлял конструктор по умолчанию (который, как я считаю, имеет тот же эффект, что и = default), код будет компилироваться и выполняться.

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

Я получил некоторую подсказку в этой публикации , но класс C здесь (без предоставленного пользователем конструктора) не тривиален, так как Деструктор виртуальный, верно?

Скомпилировано с последней версией Visual Studio, c ++ 17.

1 Ответ

17 голосов
/ 12 февраля 2020

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

new выражение вызывает соответствующий operator new и затем вызывает конструктор. Если конструктор выдает исключение new, выражение должно отменить эффект operator new (чтобы избежать утечки памяти), вызвав соответствующий operator delete. Если последнее удалено, new выражение не может вызвать его, что приводит к компилятору error: use of deleted function 'static void C::operator delete(void*)'.

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

Стандарт C ++, похоже, не указывает, должен ли компилятор требовать, чтобы operator delete не удалялся, даже если он не может быть вызван выражением new. Однако gcc, похоже, вообще не вызывает соответствующее выражение operator delete в new, если оно delete d (опубликовано сообщение об ошибке ).

...