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

Как известно система выполнения С++, когда объекты выходят из сферы действия

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

Спасибо.

4b9b3361

Ответ 1

Это известно статически во время компиляции

{
  string s; /* ctor called here */
} /* dtor called here */

Иногда это сложнее

{
  again:
  {
    string s; /* ctor called here */
    goto again; /* now dtor of s is called here */
    string q; /* ctor not called. not reached. */
  } /* dtor of s and q would be called here. but not reached */
}

Ответ 2

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

Демонтаж фрагмента из MSVC:

int main() {
    std::string s1;
...
00971416  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (979290h)] 
...
    {
        std::string s2;
00971440  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (979290h)] 
...    
    }
00971452  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (979294h)] 
...
}
0097146B  call        dword ptr [__imp_std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (979294h)] 

Ответ 3

Это не имеет никакого отношения к времени исполнения. Компилятор отслеживает объем каждой лексической переменной и добавляет вызовы деструктора.

Ответ 4

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

например. следующий код

if(something)
{
    MyClass test;
    test.doSomething();
}

Появится машинный код, который сделает что-то вроде этого:

  • оценить прыжок
  • спрыгните, если требуется
  • выделить память для тестирования
  • вызов конструктора MyClass при тестировании
  • вызов doSomething на тест
  • вызов деструктора MyClass при тестировании
  • освободить память

Ответ 5

"вызов деструктора" и "освобождение памяти, связанной с переменной", - это две разные вещи целиком.

Деструктор - это просто функция, которая С++ достаточно хороша, чтобы вызывать вас, когда ваш объект выходит из области видимости или явно удаляется. Компилятор генерирует это для вас, как говорили другие. Это удобный способ для вас очистить что-нибудь в своем классе, которое вам нужно очистить.

Освобождение памяти, связанной с чем-то в стеке, связано с изучением того, как работает стек. Когда вызывается функция, память выделяется для всего в стеке, просто нажимая на стек объем данных, необходимых для этих переменных. Хотя явно не указано в спецификации С++, "push" действительно просто включает в себя указание указателя на верхнюю часть стека выше (или ниже), чтобы освободить место для дополнительных переменных. Это простое добавление указателя. Когда функция возвращается, происходит вычитание указателя.

void foo()
{
    HerClass y;
    YourClass x; // stack incremented sizeof(YourClass) + sizeof(HerClass)

    return; // destructor called, 
            // then stack decremented sizeof(YourClass) + sizeof(HerClass)
}

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

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

Ответ 6

Когда приложение входит в среду с областью (блок, вызов функции и т.д.), среда выполнения загружает контекст (включая локальные переменные) для этого блока в стек. Это фактическая структура данных стека. Поскольку выполнение происходит глубже и глубже в вложенных контекстах, стек становится все выше и выше. Если main() вызывает foo(), который вызывает bar(), стек будет иметь контекст main() в нижней части стека, затем foo контекст, затем bar. Вот почему бесконечная рекурсия приводит к "переполнению стека" и срабатыванию триггеров исключений "разматывание стека".

Когда выполнение завершает эту область, этот контекст выталкивается из стека. В С++ всплывающие объекты стека включают вызов деструктора для этих объектов. Поэтому, когда bar() returns, его локальные переменные будут удалены из стека, и будут вызваны деструкторы для этих переменных.

Ответ 7

Вероятно, вы неправильно понимаете характеристики нескольких языков программирования. У С++ нет сборщика мусора, поэтому он не решает, когда объект вышел из сферы действия: пользователь делает.

int main()
{
    Obj * obj = new Obj;
    Obj obj2;

    delete obj;
}

В вышеприведенной функции вы создаете объект obj в куче и отпустите его, когда вы больше не собираетесь его использовать. С другой стороны, объект obj2 просто заканчивает свою жизнь в конце main(), как и любую другую переменную. Когда объект завершает свою жизнь, деструктор объекта вызывается автоматически; компилятор автоматически вставляет вызовы этих деструкторов: в конце функции или при вызове оператора delete.