От новичка до гуру: Курсы программирования на 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
  • Новые материалы

    Matt’s Tidbits #99  — «Элегантная обработка нуля»
    На прошлой неделе я писал о некоторых крайних случаях правдоподобия в JavaScript . На этот раз у меня есть небольшая заметка об элегантной обработке нулевых/неопределенных значений. null..

    Обучение работе с AWS с Habana Gaudi
    Использование возможностей выделенных обучающих чипов DNN — часть 2 В октябре прошлого года AWS объявила о появлении типа инстанса Amazon EC2 DL1 . DL1, оснащенный восемью ускорителями..

    Сортировка вставками с помощью JavaScript
    Простые типы алгоритмов сортировки Пузырьковая сортировка ➝ O(n²) Сортировка вставками ➝ O(n²) Сортировка выбором ➝ O (n²) Сортировка слиянием ➝ O (n * log n) Быстрая сортировка ➝..

    Я попросил ChatGPT решить 5 вопросов по программированию LeetCode
    ChatGPT , диалоговый ИИ от OpenAI , выпущенный в ноябре 2022 года, может понять и ответить практически на все, что вы спросите. У него есть возможность писать стихи, штамповать эссе и писать..

    DevTools, которые изменили мою жизнь
    Самые эффективные инструменты разработчика, которые я встречал за свою карьеру Время от времени вы сталкиваетесь с инструментом, который расширяет ваши способности сверхспособностями и..

    Веб-приложение для чата с использованием Phoenix и Vue.js - Часть 6
    В этой части мы рассмотрим перенос вещей в отдельные компоненты. Вот все части этой серии: Github: https://github.com/jespr/vue-phoenix-chat Heroku:..

    Почему веб-сборка меняет правила игры? (Часть 1)
    Эта статья написана, чтобы помочь новичкам понять основные концепции: с чего начать? Что для вас есть и какие реальные проблемы вы можете решить? Я уже некоторое время слышу термин..