【问题标题】:Cannot explain a destructor call after a function call is done returning an object函数调用完成返回对象后无法解释析构函数调用
【发布时间】:2015-06-28 18:00:47
【问题描述】:

我尝试运行下面的代码,但我不明白析构函数何时以及为何在myA=foo(myOtherB) 行被调用。

我的问题是,在 foo 函数返回 A 对象之后,从“输入”复制构造它并打印 A 复制器,operator= 被称为打印“Aop”,然后析构函数被称为打印 A dtor。

为什么此时调用析构函数而不是在operator=调用之前的返回之后?

我遇到的另一个问题是,如果我使用 return A(2) 而不是 return input 构造函数 A 不会被调用打印 A ctor...

谁能解释一下?抱歉代码有点复杂。

#include <iostream>

using namespace std;

class A
{
    public:
        int x;
        A(){ cout<<"A ctor"<<endl; }
        A(const A& a){cout<<"A copyctor"<<endl; }
        virtual~A(){ cout<<"A dtor"<<endl;} 
        virtual void foo(){ cout<<"Afoo()"<<endl;}
        virtual A& operator=(const A&rhs){cout<<"Aop="<<endl; }
        A(int _x)
        {
            x=_x;
        }
};


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

         virtual~B(){ cout<<"B dtor"<<endl; }
         virtual void foo(){ cout<<"B foo()"<<endl; }
    protected:
         A mInstanceOfA; 

};

A foo(A& input)
{ input.foo(); return input; //return A(2); does not call the A constructor } 



int main()
{

    B myOtherB;
    A myA;
    myA=foo(myOtherB); 

}

【问题讨论】:

    标签: c++ constructor destructor


    【解决方案1】:
    return A();
    

    这叫most vexing parse
    您不是在调用 A 的构造函数(不是创建一个新实例),而是声明一个返回 A 的函数(阅读链接以获得进一步且可能更正确的解释)。

    您可以通过以下方式调用构造函数:

    return A{2};
    

    这称为Uniform initialization syntax(C++ 11 及更高版本)


    A myA;
    myA=foo(myOtherB); 
    

    在这种情况下,您首先创建一个新的 A 对象 (myA),然后将变量分配给 foo 函数的返回值。
    由于第二行,这将调用赋值运算符。
    您将foo 返回的值复制到myA 变量。

    当已经创建的myA变量被重新赋值时,旧值将被销毁,从而调用destructor

    我认为你追求的是以下内容:

    A myA = foo(myOtherB);
    

    【讨论】:

    • 我想我理解了构造函数部分,但我实际上并没有为 myA 分配任何东西,因为 operator= 只是执行一个 cout ......那么为什么要调用析构函数,因为没有为 myA 重新分配?无论您在 operator= 函数中做什么, = 是否总是意味着重新分配?
    【解决方案2】:

    您返回按值,这意味着您返回的值被复制到一个临时对象中,该对象稍后会被销毁。

    【讨论】:

    • 为什么在调用 operator= 后它会被破坏呢? “稍后”是什么意思?
    • @matts 函数按值返回,也就是说编译器为返回的对象创建一个临时对象,这个临时对象然后被赋值运算符使用,一旦赋值表达式结束临时对象被破坏。
    【解决方案3】:

    我尝试运行下面的代码,但我不明白何时以及为什么 析构函数是否在 myA=foo(myOtherB) 行被调用。

    由于RAII,将在主函数的最后一个大括号之前调用析构函数。

    为什么此时调用析构函数而不是立即调用 operator= 调用之前的返回值?

    我已经在上面回答了这个问题,对象范围是问题。每当您的对象超出范围时,都会调用析构函数。

    我遇到的另一个问题是,如果我使用 return A(2) 而不是 return 输入构造函数 A 不会被调用打印 A ctor...

    A foo(A& input)
    { input.foo(); return input; //return A(2); does not call the A constructor } 
    

    您正在返回您的函数作为引用接收的现有对象输入,因此系统无需通过调用构造函数来创建对象。

    【讨论】:

    • 在 main 的最后一个大括号中不会调用析构函数。如果我在 main 的最后一个大括号之前放了一个 getchar(),则在 getchar() 之前调用析构函数
    • @matts 编译器可以优化语句的顺序,除非您的程序没有特定的行为变化。即使析构函数在 getchar() 之前或之后调用,影响也是一样的。
    猜你喜欢
    • 2015-05-02
    • 2020-07-28
    • 1970-01-01
    • 2010-11-10
    • 1970-01-01
    • 1970-01-01
    • 2019-09-03
    • 2010-10-16
    • 2015-12-28
    相关资源
    最近更新 更多