Подтвердить что ты не робот

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

Например:

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

    return 0;
}

class Foo {
private:
    somePointer* bar;

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

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

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

Я новичок в динамической памяти, поэтому, если это не подходит для использования, прошу прощения.

4b9b3361

Ответ 1

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

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

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

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

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

Foo* leedle = new Foo();

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

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

Вы просачиваете память, выделенную new leedle.


Вы должны delete все, что было выделено с помощью new:

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

Это делается намного проще и надежнее, используя интеллектуальные указатели. В С++ 03:

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

Или в С++ 11:

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

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


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

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

Рассмотрим:

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

В этом примере все переменные имеют автоматическую продолжительность хранения. Оба b и d будут уничтожены в LINE 2. n будет уничтожен в LINE 1.

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

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

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

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

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

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

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

Ответ 2

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

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

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

Ответ 3

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

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

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

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

Ответ 4

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

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

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

Ответ 5

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