C++方法链接导致析构函数被调用两次

jan*_*ybs 2 c++ destructor method-chaining

我有简单的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;
}
Run Code Online (Sandbox Code Playgroud)

该申请的结果如下:

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
Run Code Online (Sandbox Code Playgroud)

这是标准行为(如果是这样,为什么会这样?)或者我犯了一些错误?我可以阻止这个吗?

Bat*_*eba 6

Foo f = Foo().bar();还调用拷贝构造函数Foo,这是目前的一个编译器生成,因此不会输出任何东西到控制台.这就是为什么它看起来像是在调用更多的析构函数而不是构造函数.

你可以写信const Foo& f = Foo().bar();来避免副本.使用a const还可以延长匿名临时的生命周期,这很好.


for*_*818 5

请注意,Foo该行中涉及两个类型的对象:

Foo f = Foo().bar();
    ^----------------this one
        ^------------and this one
Run Code Online (Sandbox Code Playgroud)

但是,一个是通过构造函数创建的,另一个是通过复制构造函数创建的.这就是为什么你只打印一条线用于施工,两条用于破坏.代码一切都很好,你只需要实现复制构造函数来查看一致的输出.


Sim*_*mer 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;
}
Run Code Online (Sandbox Code Playgroud)

-

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
Run Code Online (Sandbox Code Playgroud)