为什么析构函数在C ++中运行两次?

时间:2012-06-04 01:26:09

标签: c++ constructor destructor

在完成编程任务时,我似乎对基本的C ++概念感到磕磕绊绊。我在我的程序中发现了这个错误,这是因为我的析构函数运行的次数超出了我的预期。这是一个代码示例,演示了我做错了什么,直到最基本的内容。

#include <iostream>
using namespace std;

class A
{
public:
    A(int num)
    {
        number = num;
        cout << "A constructed with number " << number << ".\n";
    }
    ~A()
    {
        cout << "A destructed with number " << number << ".\n";
    }
private:
    int number;
};

class B
{
public:
    B(A pa)
        : a(pa)
    {
        cout << "B constructor run.\n";
    }
    ~B()
    {
        cout << "B destructor run.\n";
    }
private:
    A a;
};


int main()
{
    A foo(7);
    {
        B bar(foo);
    }
    //Pause the program.
    system("pause");
}

我期望发生的是A foo(7);为名为A的{​​{1}}对象分配堆栈空间并调用构造函数,传递foo。它将7分配给7并打印输出,指示构造函数已运行。现在number为名为B bar(foo);的{​​{1}}对象分配堆栈空间并调用构造函数,按值传递B,这只是{{1}的容器}。构造函数将传递给它的bar参数分配给它自己的私有数据成员foo,并将输出打印到屏幕上。

现在,当int超出结束大括号的范围时,我希望调用A的析构函数,将输出打印到屏幕,然后调用析构函数以获取其数据成员,即a。该析构函数将输出打印到屏幕,并丢弃它所包含的bar

我期望输出应该是:

bar

实际输出:

A a

造成这种额外破坏的原因是什么?

4 个答案:

答案 0 :(得分:3)

您的B构造函数按值获取A对象,这意味着foo被复制到参数pa中,然后将其复制到成员a }。编译器已经能够忽略其中一个副本(构造函数的参数),但另一个副本不能被省略,并且你有第二个A对象被破坏。

答案 1 :(得分:2)

显然它来自会员数据A a; B类。我猜你的疑问是为什么不看A的任何构造输出,因为它是用A类的默认copy-ctor构造的,最好为A类添加一个copy-ctor,这样你就会看到构造过程

A(const A& a)
{
     number = a.number;
     cout << "A copy-constructed with number " << number << ".\n";
}

答案 2 :(得分:1)

当人们变得可爱时,我讨厌它&#34; foo&#34;和&#34; bar&#34;。

但我看到了两个&#34; A&#34;正在构建 - 一个明确地,另一个隐含地由&#34; B&#34;。并且有两个析构函数被调用。

对这张照片不喜欢什么;)?

答案 3 :(得分:0)

因为在B类中,有一个成员A a 所以要破坏B对象,首先调用其成员的析构函数。