构造函数/析构函数在堆栈上的调用顺序

Constructor/Destructor call order on stack

本文关键字:调用 顺序 堆栈 析构函数 构造函数      更新时间:2023-10-16

我有以下简单的代码:

class A
{
    int a;
public:
    A(int a) : a(a) { cout << "Constructor a=" << a << endl; }
    ~A()            { cout << "Destructor  a=" << a << endl; }
    void print()    { cout << "Print       a=" << a << endl; }
};
void f()
{
    A a(1);
    a.print();
    a = A(2);
    a.print();
}
int main()
{
    f();
    return 0;
}

输出为:

Constructor a=1
Print       a=1
Constructor a=2
Destructor  a=2
Print       a=2
Destructor  a=2

我发现a=2有两个析构函数调用,而a=1没有,而每种情况都有一个构造函数调用。那么在这种情况下如何调用构造函数和析构函数呢?

a = A(2);

将使用默认的operator=a分配新值,将a::a成员值设置为2。

void f()
{
    A a(1);//a created with int constructor a.a == 1
    a.print();// print with a.a == 1
    a = A(2);//Another A created with int constructor setting a.a == 2 and immediately assigning that object to a
    //object created with A(2) deleted printing 2 it was created with
    a.print();//a.a==2 after assign
}//a deleted printing 2 it was assigned with
你可能应该读一下"三原则"来更好地理解发生了什么。
void f()
{
    A a(1);
      //  Constructor a=1
    a.print();
      //  Print       a=1
    a = A(2);
      // Constructor a=2
      // also operator=
      // Destructor  a=2
    a.print();
      // Print       a=2
      // Destructor  a=2
}

这是因为您没有破坏A(1),而是将A(2)赋值给它,让我们通过添加赋值操作符来扩展您的示例:

class A
{
    int a;
public:
    A(int a) : a(a) { cout << "Constructor a=" << a << endl; }
    ~A()            { cout << "Destructor  a=" << a << endl; }
    void print()    { cout << "Print       a=" << a << endl; }
    A &operator=(const A &other) {
        cout << "Assign operator old=" << a << " a=" << other.a << endl; 
        a = other.a;
    }
};

这将导致:

[vyktor@grepfruit tmp]$ ./a.out 
Constructor a=1
Print       a=1
Constructor a=2
Assign operator old=1 a=2 <- This line explains why destructor is not called
Destructor  a=2
Print       a=2
Destructor  a=2

如果您实现了其中一个:

  • Destructor -销毁对象的所有成员
  • 复制构造函数 -从复制构造函数形参
  • 中的等效成员构造对象的所有成员
  • 复制赋值操作符—从赋值操作符形参
  • 中的等效成员中赋值对象的所有成员

你应该实现所有这些。

void f()
{
    A a(1); // Constructor a=1 (a.a(1) is called)
    a.print(); // Print a=1
    a = A(2); // Constructor a=2 (Temporary unnamed object A(2) is constructed)
              // compiler generated a.operator=(const A&); is called and then
              // Destructor  a=2 (Temporary unnamed object is destroyed.
    a.print(); // Print a=2
              // Destructor  a=2 (a.~a() is called)
}

首先,a=1的构造函数称为

第二个打印字叫做

第三,您创建的新对象A(2)调用了它的构造函数。

第四,这个对象被赋值给对象a,所以对象a的数据成员=2

第五,对象A(2)的析构函数称为 第六,对象a的析构函数称为