Деструктор вызывается, когда объект выходит из области видимости?

например:

int main() {
    Foo *leedle = new Foo();

    return 0;
}

class Foo {
private:
    somePointer* bar;

public:
    Foo();
    ~Foo();
};

Foo::~Foo() {
    delete bar;
}

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

Я новичок в динамической памяти, поэтому, если это не полезный тестовый случай, мне жаль.

5 ответов


да, автоматические переменные будут уничтожены в конце вложенного блока кода. Но продолжай читать.

заголовок вашего вопроса спрашивает, Будет ли вызываться деструктор, когда переменная выходит за рамки. Вероятно, вы хотели спросить:--23-->

будет ли деструктор Foo вызываться в конце main ()?

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

обратите внимание, что автоматическая переменная:

Foo* leedle = new Foo();

здесь leedle - это автоматическая переменная, которая будет уничтожено. leedle - это просто указатель. То, что leedle указывает на does не имеют автоматическую продолжительность хранения, и не будут уничтожены. Итак, если вы это сделаете:

void DoIt()
{
  Foo* leedle = new leedle;
}

вы утечку памяти new leedle.


вы должны delete все, что было выделено с new:

void DoIt()
{
  Foo* leedle = new leedle;
  delete leedle;
}

это делается намного проще и надежнее с помощью смарт-указателей. В C++03:

void DoIt()
{
  std::auto_ptr <Foo> leedle (new Foo);
}

или в C++11:

void DoIt()
{
  std::unique_ptr <Foo> leedle = std::make_unique <Foo> ();
}

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


давайте попробуем прояснить немного языка здесь. В C++ переменные имеют срок хранения. В C++03 существует 3 длительности хранения:

1: автоматическая: переменная с автоматической продолжительностью хранения будет уничтожена в конце заключительного блока кода.

считаем:

void Foo()
{
  bool b = true;
  {
    int n = 42;
  } // LINE 1
  double d = 3.14;
} // LINE 2

в этом примере все переменные имеют автоматическую продолжительность хранения. Оба!--14--> и d будет уничтожено в Строка 2. n будет уничтожено в строке 1.

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

3: динамический: переменная с динамической продолжительностью хранения будет выделена, когда вы выделите ее с помощью функций динамического выделения памяти (например,new) и будет уничтожен, когда вы уничтожите его с помощью динамических функций выделения памяти (например, delete).

в моем оригинальном примере выше:

void DoIt()
{
  Foo* leedle = new leedle;
}

leedle переменная с автоматической продолжительностью хранения и будет уничтожена в конце расчалки. То, что leedle указывает на динамическую продолжительность хранения и не уничтожается в коде выше. Вы должны позвонить delete чтобы освободить его.

C++11 также добавляет четвертую продолжительность хранения:

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


да, если объект выходит за рамки, вызывается деструктор. но Нет, деструктор не будет вызываться в этом случае, потому что у вас есть только указатель в области действия этот указатель не имеет конкретного деструктора, поэтому не будет косвенного вызова Foo'деструктор С.

этот пример является доменом приложений смарт-указателей, таких как std::unique_ptr и std::shared_ptr. Это фактические классы, которые, в отличие от необработанных указателей есть деструктор, (условно) называть delete по указанному объекту.

кстати, Fooдеструктор удаляет bar, но bar никогда не был инициализирован или назначен адресу, который указывает на фактический объект, поэтому вызов delete даст неопределенное поведение, вероятно, сбой.


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

Технически говоря, поскольку вы находитесь в основном, это не утечка памяти, так как вы до тех пор, когда приложение не завершается, вы можете получить доступ к каждой выделенной переменной. В этом отношении я цитирую Александреску (из современной C++, глава о синглетах)

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

конечно, это не означает, что вы не должны называть delete, поскольку это была бы очень плохая (и опасная) практика.


Сначала обратите внимание, что код не будет компилироваться;new возвращает указатель на объект, выделенный в куче. Вам нужно:

int main() {
    Foo *leedle = new Foo();
    return 0;
}

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


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