Локальная переменная и утечка памяти

#c #memory #memory-leaks

#c #память #утечки памяти

Вопрос:

Я читаю некоторые вещи и наткнулся на это:

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

Итак, мой вопрос в том, что происходит с переменными, у которых нет деструкторов?

В качестве примера:

 class A {
    public:
        A () { }
};

void foo () {
    A a;
}

int main (void) {
    foo();
}
  

Итак, в данном случае a() ? Будет ли память, которая была выделена для a , уничтожена после foo() завершения или нет?

Чем у меня есть этот пример:

 class A {
        std::vector <int> aa;
    public:
        A () : aa(5) { }
};

void foo () {
    A b;
}

int main (void) {
    foo();
}
  

В этом случае также будет ли память, которая была выделена для b уничтожения после foo() завершения, или нет?

Еще одно уточнение, я знаю это:

 class A {
    public:
        A () { }
};
  

эквивалентно

 class A {
    public:
        A () { }
        inline ~A() = default;
};
  

Но мой вопрос в том, вызывается ли это встроенное уничтожение, когда foo() выполняется?

РЕДАКТИРОВАТЬ: Когда был inline добавлен деструктор по умолчанию?

Комментарии:

1. A a(); — Это не создает объект. Объявляется вызываемая функция, a() которая не принимает параметров и возвращает A объект.

2. @Gox Вызов foo(); in main() , вероятно, был бы оптимизирован любым приличным компилятором c , поскольку эта функция не имеет никакого эффекта.

3. Примечание: Деструктор не освобождает память уничтожаемого объекта. Чаще всего вызывается как часть цепочки, ведущей к освобождению памяти, но может вызываться отдельно для уничтожения объекта без освобождения памяти. Подробнее об этом см. в разделе Размещение new / delete .

Ответ №1:

Если вы не предоставляете деструктор, компилятор предоставит его для вас. Этот деструктор вызовет деструкторы любых переменных-членов и базовых классов.

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

Другой случай — это когда вы приобрели какой-то другой ресурс и вам нужно его освободить. Например, если вы открываете файл или сокет, вам, вероятно, потребуется написать пользовательский деструктор, чтобы закрыть его.

Однако то, что я делаю для всех таких ресурсов, заключается в том, что я создаю класс, который оборачивает ресурс и имеет деструктор, который его закрывает. Это локализует проблему, поэтому я должен помнить как можно меньше об управлении ресурсами для большей части моего кода. Это распространенная идиома в C , которая называется RAII, что означает «Получение ресурсов — это инициализация».

Вот почему вы также должны предпочесть make_unique и make_shared или такие вещи, как vector , выделению памяти с помощью new . Они предоставляют вам объекты, которые обертывают ресурс памяти, деструкторы которых автоматически освободят ресурс для вас.

Чтобы более подробно ответить на вопрос в вашем комментарии к моему ответу…

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

 void foo () {
    A b;
    {
        A c;
    } // Destructor for c is called here
} // Destructor for b is called here.
  

Комментарии:

1. @Gox — Да, для переменной в стеке деструктор вызывается, когда завершается блок, в котором он был объявлен.

2. @Gox — Я добавил более полный ответ на ваш вопрос в комментарии к моему ответу. И, пожалуйста.

Ответ №2:

Из стандарта:

Если класс не имеет деструктора, объявленного пользователем, деструктор неявно объявляется как установленный по умолчанию ([dcl.fct.def]). Неявно объявленный деструктор является inline public членом своего класса.

Другими словами,

 class A {
    public:
        A () { }
};
  

эквивалентно

 class A {
    public:
        A () { }
        inline ~A() = default;
};
  

Что касается вашего вопроса

Но мой вопрос в том, вызывается ли это встроенное уничтожение, когда foo() выполняется?

Ответ — да. Однако это верно даже для определяемого пользователем деструктора.

Комментарии:

1. @Gox, ты пытаешься выяснить, когда вызывается деструктор?

2. @Gox, кто говорит об утечке памяти для таких объектов?

3. @Gox, я слышу твое разочарование. Я надеюсь, что вы придерживаетесь языка. Как и любой приобретенный навык, это становится проще с практикой. Желаю удачи.

4. вы пытаетесь выяснить, когда вызывается деструктор? ДА. Кто говорит об утечке памяти для таких объектов? несколько старых руководств по легкому изучению C . Кто-то порекомендовал мне прочитать эту печатную версию этого руководства.

5. @Gox, встроенные деструкторы существуют уже давно. Я использую его с 1995 года. Это, безусловно, было частью стандарта C 98.