返回值优化 - C++ - 析构函数调用

发布于 2025-01-05 11:17:05 字数 378 浏览 1 评论 0原文

以下代码调用析构函数 4 次:

#include<iostream>
using namespace std;

class A{
   public:
   A(){cout<<"A"<<endl;}
   ~A(){cout<<"~A"<<endl;}
   A f(){cout<<"F"<<endl; A b; return b;}
};

int main(){
   A a,b;
   b=a.f();
}

输出:

A
A
F
A
~A
~A
~A
~A

有人可以解释一下吗? 我想应该只有三个析构函数调用。

The following code calls the destructor 4 times:

#include<iostream>
using namespace std;

class A{
   public:
   A(){cout<<"A"<<endl;}
   ~A(){cout<<"~A"<<endl;}
   A f(){cout<<"F"<<endl; A b; return b;}
};

int main(){
   A a,b;
   b=a.f();
}

OUTPUT:

A
A
F
A
~A
~A
~A
~A

Can some one please explain?
I was thinking that there should be only three destructor calls.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

半寸时光 2025-01-12 11:17:05

main() 中有两个对象,因此析构函数会因为它们而被调用两次次。 f() 中只有一个对象,因此析构函数将因此而被调用一次。总共 3 次(如您所料,但请继续阅读...)

现在第四次为从 f 返回时创建的临时对象调用析构函数。仅当根本没有 RVO 时才会发生这种情况。 RVO 是编译器的选择,这意味着它可能会优化它,也可能不会。该语言不提供 RVO 的任何保证。

不管怎样,只要提高你的优化级别即可;我确信您最多只会看到 3 个析构函数调用。

There are two objects in main(), so the destructor will be called two times just because of them. One object in f(), so the destructor will be called one time just because of it. Total 3 times (which you expect, but read on...)

Now the fourth time destructor is called for the temporary object which is created when returning from f. This can happen only when there is no RVO at all. RVO is compiler's choice which means it may optimize it, or it may not. The language doesn't give any guarantee of RVO.

Anyway, just increase your optimization level; I'm sure you will see at most 3 destructor invocations only.

飘然心甜 2025-01-12 11:17:05

main中有2个对象:A a,b;,函数体内有一个对象f()A b;,然后有一个临时对象正在被复制,其副本存储在 b 中。

当在函数体中返回b时,首先创建副本,然后销毁本地b,然后将副本分配给变量b > 在 main 中声明,然后该副本被破坏。

将以下行添加到类 A 定义中并自行查看:

A(const A&) { cout << "copying" << endl; }

With 命名返回值优化编译器尝试消除冗余的复制构造函数和析构函数调用,这意味着函数f()b code> 将被分配给变量b 在 main 中,没有创建副本。因此,使用 RVO / NRVO 在您的情况下仅创建 3 个对象。

尽管在您的情况下有一种方法可以避免在没有 RVO 的情况下破坏此副本:

A a;
A b = a.f();

在这种情况下,将创建函数 f() 返回值的副本并将其存储为变量 b。这也意味着没有调用赋值运算符,并且在 main 中只创建了 2 个对象:a 和由 f() 返回的 b 的副本。

希望这有帮助。

There are 2 objects in main: A a,b;, one object in the body of function f() : A b; and then there is temporary object that is being copied and its copy stored into b.

When returning b in the body of your function, copy is created at first, then the local b is destructed, then copy is assigned into variable b declared in main and then this copy is destructed.

Add following line to class A definition and see yourself:

A(const A&) { cout << "copying" << endl; }

With Named Return Value Optimization, the compiler tries to eliminate redundant Copy constructor and Destructor calls which means that local b from the function f() will be assigned into variable b in main without copy being created. So with RVO / NRVO only 3 objects are created in your case.

Although there is a way how to avoid destructing this copy without RVO in your case:

A a;
A b = a.f();

in this case copy of return value of function f() is created and stored as a variable b. Which also means that no assigment operator is called and only 2 objects are created in main: a and copy of b returned by f().

Hope this helps.

猫弦 2025-01-12 11:17:05

你的编译器没有优化它。您是否在启用优化的情况下编译了它?

以下是使用 gcc 编译的相同代码的输出:

A
A
F
A
~A
~A
~A

Your compiler didn't optimize it. Have you compiled it with optimizations enabled?

Here is the output of the same code, compiled with gcc:

A
A
F
A
~A
~A
~A
还不是爱你 2025-01-12 11:17:05

A 实例有一个隐藏的创建和销毁:当您从函数 f() 返回时,对象 b 的临时副本> 已创建。它被分配给 main() 中的 b,然后被销毁。

There is one hidden creation and destruction of an instance of A: when you're returning from function f(), a temporary copy of object b is created. It's assigned to b in main() and then destroyed.

油焖大侠 2025-01-12 11:17:05

您不能依赖 RVO 的发生。这就是为什么你永远不应该将函数逻辑放在析构函数或复制构造函数中(是的,这些也可以被省略)。

返回值优化只是标准允许但不强制执行的事情。

在没有优化或 O2 的情况下,我也得到了 4 个析构函数调用。

经过全面优化 - Ox - 我只得到 3。

You can't rely on RVO to occur. That's why you should never put functional logic inside destructors or copy constructors (yes, those too can be elided).

Return value optimization is just something the standard allows, but does not enforce.

With no optimization or O2, I too get 4 destructor callse.

With full optimization - Ox - I only get 3.

萌酱 2025-01-12 11:17:05

当函数返回时,f 中的局部变量被复制到临时变量中。这就是为什么有四个析构函数调用。 (复制操作调用复制构造函数 A(A&) 而不是默认构造函数 A(),因此需要三个 A。)

Local variable in f is copied into a temporary variable when the function returns. That is why there are four destructor calls. (Copy operation calls the copy constructor A(A&) not your default constructor A(), hence three As.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文