Оператор new () поводиться по-різному, коли оператор delete () видаляється залежно від існування конструктора за замовчуванням


17

Створення нового об'єкта класу 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.


3
Не впевнений, але я вважаю, що різниця полягає в тому, що конструктор, який не знав дефолт,noexcept
Себастьян Редл,

1
Неможливо відтворити за допомогою g ++. Аналогічна діагностика щодо operator delete()того, чи створюється конструктор вручну або неявно створюється. Що відповідає моїм очікуванням - оскільки newвираз може бути викинуто висловом, компілятору потрібно отримати доступ operator delete().
Петро

@SebastianRedl ви маєте рацію, додавши noexceptзробить код компіляцією, але як ...?
yeshjho

1
@Peter Виняток може бути викинуто лише конструктором, тому якщо це так, noexceptяк згадував SebastianRedl, то виклик operator deleteне потрібно включати. Також g ++ скаржиться лише на те, якщо деструктор віртуальний. Інакше завжди компілюється, навіть якщо конструктор кидає.
волоський горіх

@LeDYoM Ваше посилання стосується розбору IP-адрес, що, здається, не має значення для питання. Ви написали неправильне посилання?
LF

Відповіді:


17

Які відмінності між конструктором за замовчуванням, створеним компілятором, і конструктором за замовчуванням, визначеним користувачем, що це робить?

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вираженні взагалі якщо deleted (відправив повідомлення про помилку ).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.