Вызов деструктора явно уничтожают объект полностью?

Это старая версия, которую я знаю, но с тех пор она была реализована с помощью интерфейса TypeScript:

var MyEnum;
(function (MyEnum) {
    MyEnum[MyEnum["Foo"] = 0] = "Foo";
    MyEnum[MyEnum["FooBar"] = 2] = "FooBar";
    MyEnum[MyEnum["Bar"] = 1] = "Bar";
})(MyEnum|| (MyEnum= {}));

Это позволяет вам посмотреть на MyEnum.Bar, который возвращает 1, и MyEnum[1], который возвращает "Bar" независимо от порядка объявления.

14
задан Robert Gould 24 June 2009 в 01:11
поделиться

11 ответов

Ответ ... почти всегда.

Если ваш объект имеет не виртуальный деструктор, а затем подклассифицируется для добавления дочерние элементы, которые нужно освободить ... тогда вызов деструктора в базовом классе объекта не освободит дочерние элементы. Вот почему вы всегда должны объявлять деструкторы виртуальными.

У нас был интересный случай, когда две разделяемые библиотеки ссылались на объект. Мы изменили определение, чтобы добавить дочерние объекты, требующие освобождения. Мы перекомпилировали первую разделяемую библиотеку, которая содержала определение объекта.

ОДНАКО вторая разделяемая библиотека не была перекомпилирована. Это означает, что ему не было известно о вновь добавленном определении виртуального объекта. Команда Delete, вызванная из второй разделяемой библиотеки, просто вызывается free и не вызывает цепочку виртуальных деструкторов. Результатом была неприятная утечка памяти.

s, вызываемый из второй разделяемой библиотеки, просто вызывается free и не вызывает цепочку виртуальных деструкторов. Результатом была неприятная утечка памяти.

s, вызываемый из второй разделяемой библиотеки, просто вызывается free и не вызывает цепочку виртуальных деструкторов. Результатом была неприятная утечка памяти.

16
ответ дан 1 December 2019 в 06:16
поделиться

Да. Но святой дым, ты уверен в этом? В таком случае я бы использовал размещение новый для создания вашего виджета . Использование размещения new с последующим явным вызовом деструктора является приемлемой, хотя и необычной идиомой.

Изменить : рассмотрите возможность выделения памяти вручную, а не использование new для выделения первый объект, а затем повторно использовать его память. Это позволяет вам полностью контролировать память; например, вы можете выделять большие фрагменты за раз, а не выделять отдельный блок памяти для каждого виджета . Это была бы неплохая экономия, если бы память действительно была таким ограниченным ресурсом.

Кроме того, что, возможно, более важно, вы бы тогда выполняли размещение new «обычно», вместо этого гибридного обычного нового / размещения нового решения. Я не говорю, что это не сработает, я просто говорю, что это довольно, ах, творческое решение вашей проблемы с памятью.

10
ответ дан 1 December 2019 в 06:16
поделиться

Да, деструктор, даже если он вызван явным образом, уничтожит свои подобъекты должным образом.

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

6
ответ дан 1 December 2019 в 06:16
поделиться

Да. Деструктор вызывает любые деструкторы-члены в порядке LIFO, затем деструкторы базового класса, и нет способа предотвратить вызов этих деструкторов *. Стек объектов гарантированно раскручивается.

Инициализация и финализация отделены от выделения и освобождения памяти в C ++ именно так, чтобы при возникновении особого случая имелся однозначный синтаксис, в котором программист приложения мог выразить свое намерение компилятор.

Изменить:

  • Я полагаю, что, вызвав abort () или longjmp (), можно было бы фактически предотвратить запуск деструкторов членов и базовых классов.
3
ответ дан 1 December 2019 в 06:16
поделиться

Запуск деструктора не освобождает память, используемую разрушаемым объектом - это делает оператор удаления. Обратите внимание, однако, что деструктор может удалить «дочерние объекты», и их память будет освобождена, как обычно.

Вам необходимо прочитать при размещении new / delete, поскольку это позволяет вам контролировать выделение памяти и запуск конструкторов / деструкторов .

См. Здесь небольшую информацию:

http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.9
2
ответ дан 1 December 2019 в 06:16
поделиться

Это делают контейнеры STL. Фактически, распределитель STL должен предоставлять метод уничтожения, который вызывает деструктор объекта (allcators также предоставляют метод освобождения для освобождения памяти, которая использовалась для хранения объекта). Однако совет Страуструпа ( Язык программирования C ++ 10.4.11) -

. Обратите внимание, что явных вызовов деструкторов ... следует по возможности избегать. Иногда они необходимы. ... Новичку следует подумать трижды, прежде чем явно вызывать деструктор, а также спросить перед этим более опытного коллегу.

2
ответ дан 1 December 2019 в 06:16
поделиться

Вызов деструктора нормально. Однако остерегайтесь того типа, к которому вы его вызываете. Если этот тип не имеет (не унаследовал) виртуального деструктора, вы можете получить неожиданное поведение.

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

Кроме того, если я не ошибаюсь, вызов деструктора вручную - единственный вариант, который у вас есть, если вы использовали размещение new для вызова конструктора.

1
ответ дан 1 December 2019 в 06:16
поделиться

Я бы подумал о переопределении new для объектов, для которых требуется особое распределение и освобождение памяти - в конце концов, это то, для чего он нужен. Гибридная схема обычных новых и явно вызываемых деструкторов звучит как рецепт от будущих головных болей. Во-первых, любая стратегия обнаружения утечек памяти будет отброшена.

0
ответ дан 1 December 2019 в 06:16
поделиться

Да, он вызовет все дочерние деструкторы, поэтому он будет работать так, как вы ожидаете.

В конце концов, деструктор - это просто функция, так уж получилось, что он вызывается, когда объекты удаляются .

Поэтому, если вы используете этот подход, будьте осторожны:

#include <iostream>

class A
{
public: 
    A(){};
    ~A()
    {
        std::cout << "OMG" << std::endl;
    }
};

int main()
{
    A* a = new A;
    a->~A();
    delete a;
    return 0;
}

output:
OMG
OMG 

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

6
ответ дан 1 December 2019 в 06:16
поделиться

Избавьте себя от настоящих головных болей и используйте Boost Object Pool , который звучит как существующая реализация вашего паттерна источник / приемник. Он выделяет большие куски памяти, разрезает их до нужного размера для вашего объекта и возвращает их вам (после вызова конструктора). Когда вы удаляете объекты, вызывается их деструктор, и они помещаются в связанный список объектов для повторного использования. Он будет увеличиваться и уменьшаться автоматически и гарантирует, что экземпляры ваших объектов будут расположены близко друг к другу в памяти.

По крайней мере, это хороший пример реализации размещения new и явного использования конструкторов, которые вы могли бы изучить.

5
ответ дан 1 December 2019 в 06:16
поделиться

Зачем вообще его уничтожать? Просто писать по памяти? Вы хотите, чтобы логика выполнялась для корректной обработки высвобождения ресурсов? Я собираюсь решительно заявить, что это злоупотребление языком и плохая идея.

0
ответ дан 1 December 2019 в 06:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: