1 C++中单个对象的构造和析构顺序

1.1 单个对象的构造和析构顺序

单个对象创建时构造函数的调用顺序:

  1. 调用父类的构造函数。
  2. 调用成员变量的构造函数(调用顺序与声明顺序相同)。
  3. 调用自身的构造函数。

析构函数与对应构造函数的调用顺序相反。


2 C++中多个对象的构造和析构顺序

C++中的类可以定义多个对象,那么对象构造的顺序是怎样的?

多个对象析构时,析构顺序与构造顺序相反。

对于析构总结如下:

  • 对于栈对象和全局对象,类似于入栈与出栈的顺序,最后构造的对象最先被析构。
  • 堆对象的析构发生在使用delete的时候,与delete的使用顺序相关。

2.1 局部对象的构造顺序

对于局部对象:

  • 当程序执行流到达对象的定义语句时进行构造。
#include <stdio.h>

class Test
{
private:
    int mi;
public:
    Test(int i)
    {
        mi = i;
        printf("Test(int i): %d\n", mi);
    }
    Test(const Test& obj)
    {
        mi = obj.mi;
        printf("Test(const Test& obj): %d\n", mi);
    }
};

int main()
{
    int i = 0;
    Test a1 = i;	// Test(int i): 0
        
    while( i < 3 )
    {
        Test a2 = ++i;	// Test(int i): 1, 2, 3
    }
        
    if( i < 4 )
    {
        Test a = a1;	// Test(const Test& obj): 0
    }
    else
    {
        Test a(100);
    }

    return 0;
}

如果使用了goto跳过了对象的构造,则可能带来意想不到的后果:

#include <stdio.h>

class Test
{
private:
    int mi;
public:
    Test(int i)
    {
        mi = i;
        printf("Test(int i): %d\n", mi);
    }
    Test(const Test& obj)
    {
        mi = obj.mi;
        printf("Test(const Test& obj): %d\n", mi);
    }
    int getMi()
    {
        return mi;
    }
};

int main()
{
    int i = 0;
    Test a1 = i; // Test(int i): 0
        
    while( i < 3 )
    {
        Test a2 = ++i; // Test(int i): 1, 2, 3
    }
goto End;       
        Test a(100);
End:
    printf("a.mi = %d\n", a.getMi());	// g++中编译错误,vs中编译通过,由于跳过了对象的构造,mi的值为随机值
    return 0;
}

2.2 堆对象的构造顺序

对于堆对象:

  • 当程序执行流到达new语句时创建对象。
  • 使用new创建对象将自动触发构造函数的调用。
#include <stdio.h>

class Test
{
private:
    int mi;
public:
    Test(int i)
    {
        mi = i;
        printf("Test(int i): %d\n", mi);
    }
    Test(const Test& obj)
    {
        mi = obj.mi;
        printf("Test(const Test& obj): %d\n", mi);
    }
    int getMi()
    {
        return mi;
    }
};

int main()
{
    int i = 0;
    Test* a1 = new Test(i); // Test(int i): 0
        
    while( ++i < 10 )
        if( i % 2 )
            new Test(i); // Test(int i): 1, 3, 5, 7, 9
        
    if( i < 4 )
        new Test(*a1);
    else
        new Test(100); // Test(int i): 100
        
    return 0;
}

2.3 全局对象的构造顺序

对于全局对象:

  • 对象的构造顺序是不确定的。
  • 不同的编译器使用不同的规则确定构造顺序。

test.h:

#ifndef _TEST_H_
#define _TEST_H_

#include <stdio.h>

class Test
{
public:
    Test(const char* s)
    {
        printf("%s\n", s);
    }
};

#endif

t1.cpp:

#include "test.h"

Test t1("t1");

t2.cpp:

#include "test.h"

Test t2("t2");

t3.cpp:

#include "test.h"

Test t3("t3");

main.cpp:

#include "test.h"

Test t4("t4");

int main()
{
    Test t5("t5");
}

对于如上代码不同编译所对应的全局对象的构造顺序是不同的。


参考资料:

  1. C++深度解析教程
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐