我有简单的c ++程序,它使用方法链接,我注意到析构函数只在链式调用中被调用两次。仅当链调用包含构造函数时才会发生这种情况。如果单独调用析构函数只调用一次。
代码如下:
class Foo {
public:
Foo() { cout << "-- constructor " << this << endl; }
~Foo () { cout << "-- destructor " << this << endl; };
Foo& 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
这是标准行为(如果是这样,为什么会这样?)或者我是否犯了一些错误?我可以阻止这个吗?
答案 0 :(得分:6)
Foo f = Foo().bar();
还调用Foo
的复制构造函数,它当前是编译器生成的,因此不会向控制台输出任何内容。 那是为什么它看起来像是在调用更多的析构函数而不是构造函数。
您可以编写const Foo& f = Foo().bar();
来删除副本。使用const
也可以延长匿名临时的生命周期,这很不错。
答案 1 :(得分:5)
请注意,该行中包含两个类型为Foo
的对象:
Foo f = Foo().bar();
^----------------this one
^------------and this one
但是,一个是通过构造函数创建的,另一个是通过复制构造函数创建的。这就是为什么你只打印一条线用于施工,两条用于破坏。使用代码一切都很好,你只需要实现复制构造函数来查看一致的输出。
答案 2 :(得分:5)
还有另一个你自己没有实现的构造函数。复制构造函数。
您的来电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 Foo& f) { cout << "-- copy-constructor " << this << endl; }
~Foo() { cout << "-- destructor " << this << endl; };
Foo& 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
答案 3 :(得分:3)
这是预期的行为。即使您从bar
返回引用,也表示您没有使用它。
Foo f = Foo().bar();
按值捕获返回值,以便复制。这意味着来自Foo
的{{1}}在表达式的末尾被销毁,当您退出作用域时,您在Foo()
中的副本将被销毁。