#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)