От новичка до гуру: Курсы программирования на CyberDuff

В каком порядке вызываются деструкторы и уничтожаются переменные-члены в C ++ с использованием наследования?

Очень похожий вопрос, но не совсем так: В каком порядке вызываются деструкторы и конструкторы в C ++ Порядок вызова конструктора и деструктора элемента

Я хочу знать: уничтожаются ли переменные-члены производного класса до или после вызова деструктора базового класса?

Это на C ++ с использованием Visual Studio 2008. Спасибо.


  • Члены уничтожаются после запуска деструктора (поскольку деструктору разрешен доступ к ним, и в большинстве случаев это делается для освобождения ресурсов и т. Д.) 06.02.2015
  • Стоит отметить, что деструкторы всегда выполняются в обратном порядке, как конструкторы, даже если последний не указан (например, глобальные объекты). Так что вам нужно запомнить только одно или другое. По крайней мере, я считаю, что это правда, и мне было бы интересно увидеть контрпример ... 06.02.2015
  • @Nemo: есть один случай, который не подходит (и только один): выгрузка динамически загружаемого общего объекта (.so / .dll / ...). Тем не менее, это выходит за рамки стандарта. 06.02.2015
  • @Deduplicator: Спасибо. Только вроде как исключение, ИМО, но это стоит знать. 06.02.2015

Ответы:


1

конструктор: сначала базовый, затем производный

разрушение:

  • ~ производный
  • ~ член производный
  • ~ база
  • ~ база участников

код:

class member {
    string s;

public:
    member(string s) {
        this-> s = s;
    }

    ~member() {
        cout << "~member " << s << endl;
    }
};

class base {
    member m;
public:
    base() : m("base"){
    }

    ~base() {
        cout << "~base" << endl;
    }
};

class derived : base{
     member m2;
public:

    derived() :m2("derived") {    }

    ~derived() {
        cout << "~derived" << endl;
    }
};

int main(int argc, const char * argv[]) {
    derived s;

    return 0;
}

Ссылки и виртуальный деструктор

Если вы планируете динамически размещать (т.е. когда вы используете ключевые слова new & delete) производный объект, то всегда используйте virtual или protected деструктор на вашей базе. В противном случае динамическое удаление объекта из ссылки на базовый класс привело бы к утечкам памяти в примере ниже:

class base {
    member m;
public:
    base() : m("base"){
    }

    /* correct behaviour is when you add **virtual** in front of the signature */
    ~base() {
        cout << "~base" << endl;
    }
};

class derived : public base{
     member m2;
    char* longArray;
public:

    derived() :m2("derived") {
        longArray = new char[1000];
    }


    ~derived() {
        delete[] longArray; // never called
        cout << "~derived" << endl;
    }
};

int main(int argc, const char * argv[]) {
    base *s = new derived; // mind the downcast to **base**

    delete s; /* only the non-virtual destructor on the base and its members is called. 
               No destructor on derived or its members is called.
               What happens to the memory allocated by derived?
               **longArray** is leaked forever. 
               Even without **longArray**, it most probably **leaks** memory, as C++ doesn't define its behaviour 
               */
    return 0;
}

Вывод:

  • ~ база
  • ~ база участников

Очищаются только базовые данные и longArray утечки.

05.02.2015
  • Возможно, вы захотите добавить в картинку виртуалы. Как есть, ваш обзор просто неверен. 06.02.2015
  • Что ж, вам нужно добавить виртуальные базы и изучать по порядку. 06.02.2015

  • 2

    Вот что говорит стандарт ... (C ++ 11, 12.4 / 8)

    После выполнения тела деструктора и уничтожения любых автоматических объектов, размещенных в теле, деструктор для класса X вызывает деструкторы для прямых неизменяемых нестатических элементов данных X, деструкторы для прямых базовых классов X и, если X - это типа наиболее производного класса (12.6.2), его деструктор вызывает деструкторы для виртуальных базовых классов X. Все деструкторы вызываются так, как если бы на них ссылались с квалифицированным именем, то есть игнорируя любые возможные виртуальные переопределяющие деструкторы в более производных классах. Базы и члены уничтожаются в порядке, обратном завершению их конструктора (см. 12.6.2). Оператор return (6.6.3) в деструкторе может не возвращаться напрямую вызывающей стороне; перед передачей управления вызывающей стороне вызываются деструкторы для членов и баз. Деструкторы для элементов массива вызываются в порядке, обратном их построению (см. 12.6).

    Обратите внимание, что этот порядок действительно является обратным порядку, указанному в 12.6.2 / 10 в C ++ 11. Вы не можете определить порядок уничтожения виртуальных баз, глядя только на 12.4 / 8, но вы можете вывести его из 12.6.2 / 10, который указывает, что инициализация виртуальных баз происходит при поиске в глубину слева направо. -правильный порядок. (Таким образом, уничтожение виртуальных баз происходит в обратном порядке.)

    В любом случае, у вас есть ответ. Сначала уничтожаются нестатические члены, а затем базовые классы. Но члены базового класса будут уничтожены до запуска деструктора next базового класса. Это действительно похоже на поиск в глубину.

    05.02.2015
  • Разве в вашей цитате не сказано, что нестатические члены уничтожаются до базовых классов? 06.02.2015
  • @Nemo мой плохой, опечатка 06.02.2015
  • Я почти уверен, что деструкторы всегда выполняются в обратном порядке по сравнению с конструкторами. 06.02.2015
  • @Nemo Я почти уверен, что в любом случае это относится к относительному порядку подобъектов классов. Я не совсем уверен, правда ли это в целом. 06.02.2015
  • @Deduplicator Извините, я вас не понимаю. Какая вторая часть предложения? 06.02.2015
  • @Deduplicator Я не совсем понимаю, что вы имеете в виду, но я немного переписал свой ответ, чтобы было понятнее. 06.02.2015
  • @ Non-static members are destroyed first, then base classes., потому что static members не будет уничтожен деструктором, поскольку они часть класса, а не объект, верно? 13.05.2021
  • @AbhishekMane правильно. Статические члены уничтожаются при нормальном завершении программы. 14.05.2021
  • @BrianBi stackoverflow.com/q/67772282/11862989, пожалуйста, ответьте на этот вопрос. 02.06.2021
  • Новые материалы

    Отслеживание состояния с течением времени с дифференцированием снимков
    Время от времени что-то происходит и революционизирует часть моего рабочего процесса разработки. Что-то более забавное вместо типичного утомительного и утомительного процесса разработки. В..

    Я предполагаю, что вы имеете в виду методы обработки категориальных данных.
    Я предполагаю, что вы имеете в виду методы обработки категориальных данных. Пожалуйста, проверьте мой пост Инструментарий специалиста по данным для кодирования категориальных переменных в..

    Игра в прятки с данными
    Игра в прятки с данными Я хотел бы, чтобы вы сделали мне одолжение и ответили на следующие вопросы. Гуглить можно в любое время, здесь никто не забивается. Сколько регионов в Гане? А как..

    «Раскрытие математических рассуждений с помощью Microsoft MathPrompter и моделей больших языков»
    TL;DR: MathPrompter от Microsoft показывает, как использовать математические рассуждения с большими языковыми моделями; 4-этапный процесс для улучшения доверия и рассуждений в математических..

    Раскройте свой потенциал в области разработки мобильных приложений: Абсолютная бесплатная серия
    Глава 6: Работа в сети и выборка данных Глава 1: Введение в React Native Глава 2: Основы React Native Глава 3: Создание пользовательского интерфейса с помощью React Native Глава 4:..

    Все о кейсах: Camel, Snake, Kebab & Pascal
    В программировании вы сталкивались с ними при именовании переменной, класса или функции. Поддержание согласованности типов и стилей случаев делает ваш код более читабельным и облегчает совместную..

    Как работает дистанционное парное программирование и почему оно может изменить вашу жизнь
    Серебряная пуля от одиночества и отвлекающих факторов во время обучения программированию Независимо от того, работаете ли вы или учитесь удаленно, велика вероятность, что одиночество и..