#c #destructor #method-chaining
#c #деструктор #метод-цепочка
Вопрос:
У меня есть простая программа на c , которая использует цепочку методов, и я заметил, что деструктор вызывается дважды, когда используется только в цепочке вызовов. Это происходит только в том случае, если цепной вызов также содержит конструктор. Если вызывается отдельно, деструктор вызывается только один раз.
Код приведен ниже:
class Foo {
public:
Foo() { cout << "-- constructor " << this << endl; }
~Foo () { cout << "-- destructor " << this << endl; };
Fooamp; bar() {
cout << "---- bar call " << this << endl;
return *this;
}
};
int main() {
cout << "starting test 1" << endl;
{
Foo f = Foo();
}
cout << "ending test 1" << endl << endl;
cout << "starting test 2" << endl;
{
Foo f = Foo().bar();
}
cout << "ending test 2" << endl;
return 0;
}
Результат этого приложения следующий:
starting test 1
-- constructor 0x7ffd008e005f
-- destructor 0x7ffd008e005f
ending test 1
starting test 2
-- constructor 0x7ffd008e005f
---- bar call 0x7ffd008e005f
-- destructor 0x7ffd008e005f
-- destructor 0x7ffd008e005f
ending test 2
Является ли это стандартным поведением (если да, то почему?) Или я допустил какую-то ошибку? Могу ли я предотвратить это?
Комментарии:
1. Добавьте конструктор копирования и оператор присваивания, чтобы увидеть, что происходит
2. Копия, упомянутая во всех приведенных ниже ответах, исключается в первом случае. Если вы скомпилируете с
g -fno-elide-constructors
помощью, вы увидите, что вызывается 2 деструктора.3. Что ж, это довольно интересно. Спасибо!
4. Это не проблема, но не используйте
std::endl
, если вам не нужны дополнительные вещи, которые он делает.'n'
завершает строку.
Ответ №1:
Foo f = Foo().bar();
также вызывает конструктор копирования Foo
, который в настоящее время генерируется компилятором и поэтому ничего не выводит на консоль. Вот почему похоже, что вы вызываете больше деструкторов, чем конструкторов.
Вы могли бы написать const Fooamp; f = Foo().bar();
, чтобы избежать копирования. Использование a const
также продлевает срок службы анонимного временного, что приятно.
Ответ №2:
Обратите внимание, что в Foo
строке задействованы два объекта типа:
Foo f = Foo().bar();
^----------------this one
^------------and this one
однако один создается с помощью конструктора, а другой — с помощью конструктора копирования. И именно поэтому вы получаете только одну строку, напечатанную для построения, и две для уничтожения. С кодом все в порядке, вам просто нужно реализовать конструктор копирования, чтобы увидеть согласованный результат.
Ответ №3:
Существует еще один конструктор, который вы не реализовали самостоятельно. Конструктор копирования.
Ваш звонок Foo f = Foo().bar();
может быть записан как Foo tmp = Foo(); Foo f = tmp.bar();
Только создание экземпляра вашего tmp
объекта вызовет ваш конструктор. Вызываемый конструктор f
— это автоматически сгенерированный конструктор-копия.
Это должно дать вам лучший результат:
#include <iostream>
using std::cout;
using std::endl;
class Foo {
public:
Foo() { cout << "-- constructor " << this << endl; }
Foo(const Fooamp; f) { cout << "-- copy-constructor " << this << endl; }
~Foo() { cout << "-- destructor " << this << endl; };
Fooamp; bar() {
cout << "---- bar call " << this << endl;
return *this;
}
};
int main() {
cout << "starting test 1" << endl;
{
Foo f = Foo();
}
cout << "ending test 1" << endl << endl;
cout << "starting test 2" << endl;
{
Foo f = Foo().bar();
}
cout << "ending test 2" << endl;
return 0;
}
—
starting test 1
-- constructor 000000EC09CFF944
-- destructor 000000EC09CFF944
ending test 1
starting test 2
-- constructor 000000EC09CFFA44
---- bar call 000000EC09CFFA44
-- copy-constructor 000000EC09CFF964
-- destructor 000000EC09CFFA44
-- destructor 000000EC09CFF964
ending test 2
Ответ №4:
Это ожидаемое поведение. Даже если вы возвращаете ссылку из bar
, вы ее не используете.
Foo f = Foo().bar();
фиксирует возвращаемое значение по значению, поэтому вы создаете копию. Это означает, что Foo
from Foo()
уничтожается в конце выражения, а его копия, которую вы создаете, f
уничтожается при выходе из области видимости.