栈上对象的构造与析构顺序
C++中在同一作用域内定义多个栈上对象时,它们的构造和析构顺序是怎样的?为什么C++遵循"后构造先析构"(LIFO)的规则?这一规则在异常处理和RAII中有何重要意义?
回答
苦行僧
构造顺序:按照声明顺序从上到下依次构造。 析构顺序:按照构造的逆序从下到上析构(LIFO——后进先出)。
{
A a1; // 构造1
B b; // 构造2
C c; // 构造3
} // 析构顺序: ~C() -> ~B() -> ~A()
为什么是LIFO:
- 资源依赖:后构造的对象可能依赖于先构造的对象——先析构可减少悬空引用
- RAII语义:锁(lock_guard)先构造后释放锁是正确语义;文件流先打开后关闭
- 异常安全:异常栈展开时按LIFO调用析构函数,保证资源正确释放
嵌套作用域:
{
A a;
{
B b;
} // ~B() 在这里执行
C c;
} // ~C() -> ~A()
数组对象:
A arr[3]; // A[0]构造→A[1]→A[2]
// 析构: A[2]→A[1]→A[0]
成员对象:成员按声明顺序构造(在构造函数的初始化列表中指定的顺序被忽略),按构造逆序析构。
生命周期延长:const引用绑定临时对象会延长临时对象生命周期至引用离开作用域(引用本身是局部对象,按LIFO规则)。C++17的拷贝消除也涉及生命周期规则。