Разве нестатические члены класса уничтожаются даже без деструктора? - PullRequest
5 голосов
/ 23 апреля 2019

В книге Бьярна Страуструпа «Язык программирования C ++ (4-е издание)» в разделе 17.6 («Генерация операций по умолчанию») упоминается следующее:

Если программист объявляет операцию копирования, операцию перемещения или деструктор для класса, без операции копирования, перемещения или деструктор генерируется для этого класса.

Таким образом, я запутался, почему в этой программе вызывается деструктор SubObj:

#include <iostream>
using namespace std;

class SubObj {
    public:
        ~SubObj() {
            cout << "SubObj Destructor called" << endl;
        }
};

class Obj {
    private:
        SubObj so;

    public:
        Obj() {};
        Obj(const Obj& o) {};
};

int main() {
    Obj();
    cout << "Program end" << endl;
}

При компиляции с g ++ я получаю следующий вывод:

$ ./a.out
SubObj Destructor called
Program end

Исходя из моего понимания, я ожидал, что деструктор по умолчанию для Obj не будет сгенерирован автоматически, потому что я определил операцию копирования для Obj. И поэтому я ожидал, что SubObj член Obj не будет уничтожен, потому что для Obj.

не существует деструктора.

Итак, мне интересно: члены объекта автоматически уничтожаются даже без деструктора? Или деструктор как-то генерируется автоматически для этого примера?

Изменить:

Далее в книге (17.6.3.4), ссылаясь на пример, Бьярне упоминает:

Мы определили назначение копирования, поэтому мы также должны определить деструктор. Этот деструктор может быть =default, потому что все, что ему нужно сделать, это убедитесь, что член pos удален, что все равно было сделано, если назначение копии не было определено.

Судя по полученным ответам, кажется, что Бьярне, возможно, только что ошибся в этом.

Ответы [ 3 ]

5 голосов
/ 23 апреля 2019

Формулировка Бьярне могла бы быть лучше здесь. Что

Если программист объявляет операцию копирования, операцию перемещения или деструктор для класса, для этого класса не создается операция копирования, операция перемещения или деструктор.

Может быть точнее (но все еще не так, см. Ссылку ниже для полных правил)

Если программист объявляет операцию копирования, операцию перемещения или деструктор для класса, для этого класса не генерируется операция копирования, операция перемещения или деструктор (соответственно) .

означает, что если вы объявите какую-либо из этих специальных функций-членов, компилятор не добавит свою собственную версию. Если вы объявляете конструктор копирования, он не останавливает деструктор, только конструктор копирования (и перемещается в C ++ 11+). Только определение деструктора останавливает компилятор от его генерации. Чтобы увидеть все правила, смотрите: Каковы все функции-члены, созданные компилятором для класса? Это происходит постоянно?

5 голосов
/ 23 апреля 2019

Эта фраза из книги плохо сформулирована / неверна.

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

Если вы предоставите свой собственный деструктор, деструктор не будет создан.Этого не должно быть, и у вас не может быть двух.

Кроме того, члены уничтожаются независимо от того, что делает ваш деструктор.Деструктор позволяет вам делать «лишние» вещи, в дополнение к обычным правилам времени жизни объекта (и подобъекта).Никогда не было риска, что член SubObj не будет уничтожен.

2 голосов
/ 23 апреля 2019

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

Единственный раз, когда компилятор не генерирует неявный деструктор, это когда он явный:

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

https://en.cppreference.com/w/cpp/language/destructor

...