如何判断局部变量何时被销毁?

CPP*_*PPL 1 c++ function local-variables

根据我目前的理解,粗略地说,static当执行线程离开其作用域时,(非)局部变量将被销毁。但是我发现局部变量在不同的情况下被销毁的具体点是不一样的。我一直在努力理解如何确定局部变量何时被销毁,特别是其背后的原因。(我问的可能相关问题包括:1、2、3

给定 2 个玩具类:

class A {
public:
    A() { cout << "A created\n"; }
    A(const A&) { cout << "A copied\n"; }
    ~A() { cout << "A destroyed" << endl; }
};

class B{
public:
    B() { cout << "B created\n"; }
    B(const B&) { cout << "B copied\n"; }
    ~B() { cout << "B destroyed\n"; }
};
Run Code Online (Sandbox Code Playgroud)
  • 示例1:
B& f() {
    A a;
    static B b;
    return b;
}

int main()
{
    B b = f();
}
Run Code Online (Sandbox Code Playgroud)

这里的输出如下:

A created
B created
A destroyed
B copied
B destroyed
B destroyed
Run Code Online (Sandbox Code Playgroud)

根据我目前的理解,在示例1中,局部(非static)变量在返回引用后立即被销毁,然后被引用的对象被复制到b.

  • 示例2:
A created
B created
A destroyed
B copied
B destroyed
B destroyed
Run Code Online (Sandbox Code Playgroud)

这里的输出如下:

A created
B created
B copied
B destroyed
A destroyed
B destroyed
Run Code Online (Sandbox Code Playgroud)

这次,复制b发生在局部变量被销毁之前。

根据我的理解,对于 C++17 及更高版本,返回的g()是纯右值,而不是对象。因此,如果局部变量的销毁发生在g()创建 的纯右值之后但在复制之前(如示例 1 所示),我们将复制已被销毁的内存。因此,我将输出视为“编译器正在等待复制完成,然后再销毁局部变量”。

然而,这只是我的一个非常模糊的理解。请问幕后到底发生了什么,才能让这样的“等待”始终正常进行

  • 示例3:(仅供演示)
B g() {
    A a;
    B b;
    return b;
}

int main()
{
    B b = g();
}
Run Code Online (Sandbox Code Playgroud)

这里的输出如下:

A created
B created
B copied
B copied
B destroyed
A destroyed
B destroyed
B destroyed
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我认为b是用来复制初始化一个临时的,然后这个临时用于复制初始化cb。即使临时变量实际上是一个对象,而不是纯右值,局部变量也会在所有这些复制之后被销毁。所以,这种情况也与示例1不同。


我正在使用 Visual Studio 2022,C++20。

Mil*_*nek 5

函数局部变量在函数的返回值初始化后立即销毁。

在第一个示例中,该返回值只是一个引用,因此它的创建没有明显的副作用。函数返回后,b然后使用返回的引用进行初始化,因此您会 f返回后看到“B Copy”输出。

在第二个示例中,函数的返回值是一个B对象。特别是由于纯右值的工作方式b而导致的变量。main这意味着b直接由 初始化,因此您会在返回之前g看到“B Copy”输出。 g

第三个例子涉及到异常,而且异常比较复杂,具体的机制也不是很标准化。您可以确定 的fun局部变量将在catch进入块之前被销毁,但除此之外,异常对象可能在堆栈展开期间被复制任意多次。