Как деструкторы работают в простой программе?

#c #constructor #destructor

#c #constructor #деструктор

Вопрос:

Я не понимаю выходных данных этой программы :

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

A f (A amp; a) { 
    return a;
}

int main() {
    A a ;
    a = f(a);

    return 0;
}
  

Я ожидал

 A()
~A()
  

потому что я создал только один A объект : a . Однако на выходе получается

 A()
~A()
~A()
  

Вы знаете, почему это так?


СЛЕДУЮЩИЙ ВОПРОС

Итак, при каждом вызове f я создаю копию A , поэтому у меня есть 1 вызов конструктора копирования и один вызов деструктора…

Допустим, теперь моя основная функция :

 int main() {
    A a ;
    A b = f(a);
    cout << "returning 0" << endl;
    return 0;
}
  

Я бы ожидал, что результат будет

 A(),
A(const A amp;) (for using f(a))
~A()         (for deleting temporary f(a))
returning 0
~A()         (destroying B)
~A()         (destroying A)
  

Но на выходе получается

 A() 
A(constamp; A) 
returning 0
~A()
~A()
  

Почему это?

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

1. Попробуйте добавить эту строку: A(const Aamp;) { cout << "A(const Aamp;)" << endl; } .

2. Вам не хватает построения копии и назначения копии (и, чтобы быть полным, также операций перемещения).

Ответ №1:

Вы явно создали только один объект, но здесь вы создаете один объект:

 A f (A amp; a) { return a ;} //when returning A
  

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

 class A {
public :
    A () { cout << "A() " << endl;}
    A (const A amp;) { cout << "A(const amp;) " << endl;}
    ~A () { cout << "~A ()" << endl; }
};
  

вы увидите, что вызывается конструктор копирования (поскольку вы его предоставляете).

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

1. Да, конечно, виноват, я исправил ответ. Спасибо @Evg

2. Пабло Ягги, @Evg а как насчет продолжения ? У меня возникли проблемы с объединением всего этого.

Ответ №2:

Ответ на следующий вопрос.

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

 A b = f(a);
  

это не присваивание (в отличие от a = f(a) ), а конструкция (инициализация копирования). Здесь вы не видите создания и уничтожения временного объекта благодаря оптимизации возвращаемого значения (RVO): компилятору разрешено удалять ненужную копию и создавать b как если бы с помощью A b(a); .

До C 17 этот механизм был необязательным. Вы можете скомпилировать этот код с помощью GCC с -std=c 11 -fno-elide-constructors опциями для определения временного:

 A()              construct (a)
A(const Aamp;)      construct a temporary copy of (a)
A(const Aamp;)      construct (b) from that temporary
~A()             destruct that temporary
returning 0 
~A()             destruct (b)
~A()             destruct (a)
  

Начиная с C 17, этот тип исключения копирования является обязательным, поэтому вы всегда будете видеть только две конструкции и разрушения:

 A()              construct (a)
A(const Aamp;)      construct (b) from (a)
returning 0 
~A()             destruct (b)
~A()             destruct (a)