【问题标题】:Why does the number of constructor calls not match with the number of destructor calls?为什么构造函数调用的次数与析构函数的调用次数不匹配?
【发布时间】:2017-12-08 08:09:26
【问题描述】:

我对下面这段代码很困惑。

#include <iostream>

class mobject
{
public:
    mobject(){ std::cout << "mobject ctor\n"; }
    ~mobject(){ std::cout << "mobject dtor\n"; }
};

mobject giveme() { return mobject(); }
void func2(const mobject& p) { mobject g = p; }
void func1(const mobject& p) { func2(p); }
int main()
{
    func1(giveme());
    return 0;
}

它给了我以下输出:

对象 ctor mobject dtor mobject dtor

我使用 gcc 5.4.0 编译了代码,并带有“g++ -g temp.cpp”。我主要关心的是第二次调用 mobjects 的析构函数。这看起来是完全错误的,因为我们第二次调用 dtor。 valgrind 告诉我这个没有问题,但我仍然很困惑。

【问题讨论】:

  • 您构造了 2 个对象,一个临时对象和一个命名本地对象 g。然后调用了两个析构函数。
  • 你听说过复制构造函数吗,它有签名mobject(const myobject&amp;),你创建了一个复制对象,因此调用了2个析构函数。

标签: c++


【解决方案1】:

您的代码构造了两个mobjects,一个是默认构造的,另一个是构造的副本,但是您只在默认构造函数中放置了一条打印消息,而忽略了复制构造函数。另请注意,您的函数调用与手头的问题无关:

#include <iostream>

struct mobject
{
    mobject(const mobject& /* other */){ std::cout << "mobject copy-ctor\n"; }
    mobject(){ std::cout << "mobject ctor\n"; }
    ~mobject(){ std::cout << "mobject dtor\n"; }
};

int main()
{
  const mobject& p = mobject();
  mobject g = p;
}

给出:

对象 ctor mobject 复制器 mobject dtor mobject dtor

【讨论】:

    【解决方案2】:

    mobject dtor 的两行输出是由于以下原因:

    • func1(giveme()); 行中的main 中调用giveme() 函数时会创建第一个对象。这会在程序结束时给出第三行输出mobject dtor
    • 第二个对象是在函数func2mobject g = p; 行中使用default-copy-constructor 创建的。第 2 行输出 mobject dtor 是该对象被删除以作为此函数的回报。

    以下修改后的代码和相应的输出将演示它:

    class mobject
    {
    public:
        mobject(const mobject& ob){ cout << "mobject overridden-copy-constructor\n"; }
        mobject(){ cout << "mobject ctor\n"; }
        ~mobject(){ cout << "mobject dtor\n"; }
    };
    
    mobject giveme() 
    { 
        cout << "1. In Function: "<<__func__<<endl;
        return mobject(); 
    }
    void func2(const mobject& p) 
    { 
        cout << "2. In Function: "<<__func__<<endl;
        mobject g = p; 
        cout << "3. In Function: "<<__func__<<endl;
    }
    void func1(const mobject& p) 
    { 
        cout << "4. In Function: "<<__func__<<endl;
        func2(p); 
        cout << "5. In Function: "<<__func__<<endl;
    }
    int main()
    {
        cout << "6. In Function: "<<__func__<<endl;
        func1(giveme());
        cout << "7. In Function: "<<__func__<<endl;
        return 0;
    }
    

    输出

    6. In Function: main
    1. In Function: giveme
    mobject ctor
    4. In Function: func1
    2. In Function: func2
    mobject overridden-copy-constructor
    3. In Function: func2
    mobject dtor
    5. In Function: func1
    mobject dtor
    7. In Function: main
    

    查看here工作代码吧。

    【讨论】:

    • 如果您使用std::endl,您将刷新流,并使流更难以缓冲输出。这本身并没有错,只是人们应该注意的事情。
    猜你喜欢
    • 2013-12-11
    • 1970-01-01
    • 2015-04-28
    • 2022-07-05
    • 2021-04-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-06
    相关资源
    最近更新 更多