为什么销毁顺序与构造顺序相同,静态对象(C++)?
Why is the order of destruction same as order of construction, with static object (C++)?
密码是:
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "A::A" << endl; }
~A() { cout << "A::~" << endl; }
};
class B
{
public:
B() { cout << "B::B" << endl; }
~B() { cout << "B::~" << endl; }
};
int main()
{
B b;
static A a;
return 0;
}
输出为:
B::B
A::A
B::~
A::~
非静态对象的范围b
和静态对象的范围a
在main()
函数结束时结束。
问题:为什么构造函数的顺序和析构函数的顺序相同?
Static local variables 将在程序退出时销毁。
The destructor for a block-scope static variable is called at program exit, but only if the initialization took place successfully.
所以b
会在main()
结束时先被销毁,a
会在a
之后被销毁
对于初始化,
are initialized the first time control passes through their declaration
所以b
将在main()
中首先被初始化,然后a
被初始化。
因为它们的寿命不同。 A
声明为函数局部静态变量。
通过声明自动函数局部变量创建的对象的生命周期开始于该对象的任何使用之前,结束于包含该声明的嵌套最多的代码块(大括号块)。在你的情况下,函数 main()
body.
在执行流进入包含该声明的最嵌套代码块之后并且在使用该对象之前,通过声明静态函数局部变量创建的对象开始存在。
它具有进程范围的生命周期(在 std::atexit()
时停止存在),这发生在函数 main()
将退出之后。
因此,在这种特殊情况下,它们是按声明顺序创建的,但 A
稍后会被销毁。如果您的函数被调用两次,您会看到 B
会被创建两次,而 A
只会被创建一次。如果函数的流程以某种方式省略声明,通过 if()
语句或通过提前返回,它们的创建顺序将改变或两者都可能被省略。
它是特定于实现的细节,但通常以与全局对象的销毁相同的方式实现函数局部静态的销毁,通过调用位于 std::atexit 实现下的库函数,添加析构函数的地址与指向对象本身的指针的值绑定,但执行可能与用户调用 std::atexit
.
的结果并发(或可能不是)
作为对现有答案的补充,让我们采用更现象学的方法。考虑对您的示例进行一些小改动:
void foo() {
B b;
static A a;
}
int main() {
foo();
foo();
}
我假设您知道 a
仅初始化一次,在第二次调用时我们得到完全相同的对象 a
,因为它被声明为 static
。因此,它不能在第一次调用 foo
期间或之后直接销毁。预期的第一部分输出是
B::B // first call to foo()
A::A
B::~
B::B // second call to foo()
// no second call to A::A !
B::~
a
只能在你的程序终止时销毁,否则你不能在再次调用函数时“重用”它(这就是为什么我必须修改示例,你不能调用 main
).正如其他答案所详细解释的那样,这发生在 main
returns 之后。因此最后一行输出将是
A::~
密码是:
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "A::A" << endl; }
~A() { cout << "A::~" << endl; }
};
class B
{
public:
B() { cout << "B::B" << endl; }
~B() { cout << "B::~" << endl; }
};
int main()
{
B b;
static A a;
return 0;
}
输出为:
B::B
A::A
B::~
A::~
非静态对象的范围b
和静态对象的范围a
在main()
函数结束时结束。
问题:为什么构造函数的顺序和析构函数的顺序相同?
Static local variables 将在程序退出时销毁。
The destructor for a block-scope static variable is called at program exit, but only if the initialization took place successfully.
所以b
会在main()
结束时先被销毁,a
会在a
之后被销毁
对于初始化,
are initialized the first time control passes through their declaration
所以b
将在main()
中首先被初始化,然后a
被初始化。
因为它们的寿命不同。 A
声明为函数局部静态变量。
通过声明自动函数局部变量创建的对象的生命周期开始于该对象的任何使用之前,结束于包含该声明的嵌套最多的代码块(大括号块)。在你的情况下,函数 main()
body.
在执行流进入包含该声明的最嵌套代码块之后并且在使用该对象之前,通过声明静态函数局部变量创建的对象开始存在。
它具有进程范围的生命周期(在 std::atexit()
时停止存在),这发生在函数 main()
将退出之后。
因此,在这种特殊情况下,它们是按声明顺序创建的,但 A
稍后会被销毁。如果您的函数被调用两次,您会看到 B
会被创建两次,而 A
只会被创建一次。如果函数的流程以某种方式省略声明,通过 if()
语句或通过提前返回,它们的创建顺序将改变或两者都可能被省略。
它是特定于实现的细节,但通常以与全局对象的销毁相同的方式实现函数局部静态的销毁,通过调用位于 std::atexit 实现下的库函数,添加析构函数的地址与指向对象本身的指针的值绑定,但执行可能与用户调用 std::atexit
.
作为对现有答案的补充,让我们采用更现象学的方法。考虑对您的示例进行一些小改动:
void foo() {
B b;
static A a;
}
int main() {
foo();
foo();
}
我假设您知道 a
仅初始化一次,在第二次调用时我们得到完全相同的对象 a
,因为它被声明为 static
。因此,它不能在第一次调用 foo
期间或之后直接销毁。预期的第一部分输出是
B::B // first call to foo()
A::A
B::~
B::B // second call to foo()
// no second call to A::A !
B::~
a
只能在你的程序终止时销毁,否则你不能在再次调用函数时“重用”它(这就是为什么我必须修改示例,你不能调用 main
).正如其他答案所详细解释的那样,这发生在 main
returns 之后。因此最后一行输出将是
A::~