gpt4 book ai didi

c++ - 当我真的只需要一个对象时,为什么创建了两个对象?

转载 作者:太空狗 更新时间:2023-10-29 19:59:39 24 4
gpt4 key购买 nike

我刚刚编译了这个简单的片段:

#include <iostream>
#include <string>

std::string foo()
{
return std::string("bar");
}

int main()
{
std::string test = foo();
std::cout << test << std::endl;
return 0;
}

使用-O2 优化,只发现创建了两个 std::string 对象。当我转储二进制文件时,objdump 显示 ~basic_string 被调用了两次。

0000000000400900 <main>:
400900: 53 push %rbx
400901: 48 83 ec 10 sub $0x10,%rsp
400905: 48 89 e7 mov %rsp,%rdi
400908: e8 73 01 00 00 callq 400a80 <foo()>
40090d: 48 89 e6 mov %rsp,%rsi
400910: bf 80 10 60 00 mov $0x601080,%edi
400915: e8 a6 ff ff ff callq 4008c0 <std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@plt>
40091a: 48 89 c7 mov %rax,%rdi
40091d: e8 ae ff ff ff callq 4008d0 <std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)@plt>
400922: 48 89 e7 mov %rsp,%rdi
400925: e8 76 ff ff ff callq 4008a0 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()@plt>
40092a: 48 83 c4 10 add $0x10,%rsp
40092e: 31 c0 xor %eax,%eax
400930: 5b pop %rbx
400931: c3 retq
400932: 48 89 c3 mov %rax,%rbx
400935: 48 89 e7 mov %rsp,%rdi
400938: e8 63 ff ff ff callq 4008a0 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()@plt>
40093d: 48 89 df mov %rbx,%rdi
400940: e8 ab ff ff ff callq 4008f0 <_Unwind_Resume@plt>
400945: 66 66 2e 0f 1f 84 00 data32 nopw %cs:0x0(%rax,%rax,1)
40094c: 00 00 00 00

因为我真的只需要一个对象,所以我想通过使用右值引用来捕获返回的值 foo()。所以我将代码行更改为 std::string && test = foo(); 奇怪的是,objdump 仍然显示调用了两个析构函数。谁能解释一下为什么?

最佳答案

第一个析构函数调用之后是 retq 的几条指令:

  400925:   e8 76 ff ff ff          callq  4008a0 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()@plt>
...
400931: c3 retq

这是正常代码流。

从位于 400932 的后续 mov 开始是内部用于通过异常传播展开堆栈的代码,通常称为 landing pad

  400932:   48 89 c3                mov    %rax,%rbx
400935: 48 89 e7 mov %rsp,%rdi
400938: e8 63 ff ff ff callq 4008a0 <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()@plt>
40093d: 48 89 df mov %rbx,%rdi
400940: e8 ab ff ff ff callq 4008f0 <_Unwind_Resume@plt>

Here这是 GCC 必须说的:

  • Generate exception handling landing pads

    This pass generates the glue that handles communication between the exception handling library routines and the exception handlers within the function. Entry points in the function that are invoked by the exception handling library are called landing pads. The code for this pass is located within except.c.

如您所见,控制流的路径是完全不同的,因此析构函数在任何一种方式中都只会被调用一次。

_Unwind_Resume 是 AMD64 和 Itanium C++ ABI 的一部分,作为展开调用堆栈的一种方式,直到它到达能够捕获异常类型的函数。您需要进行一些挖掘才能从 Google 中找到有关它的大量信息。 Here是讨论它的非常好的资源。

_Unwind_Resume

void _Unwind_Resume
(struct _Unwind_Exception *exception_object);

Resume propagation of an existing exception e.g. after executing cleanup code in a partially unwound stack. A call to this routine is inserted at the end of a landing pad that performed cleanup, but did not resume normal execution. It causes unwinding to proceed further.

_Unwind_Resume should not be used to implement rethrowing. To the unwinding runtime, the catch code that rethrows was a handler, and the previous unwinding session was terminated before entering it. Rethrowing is implemented by calling _Unwind_RaiseException again with the same exception object.

This is the only routine in the unwind library which is expected to be called directly by generated code: it will be called at the end of a landing pad in a "landing-pad" model.

关于c++ - 当我真的只需要一个对象时,为什么创建了两个对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12169634/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com