按值函数创建范围的临时对象
Temporary object for by-value function creation scope
我有以下代码,我无法理解:
#include <cstdio>
#include <iostream>
using namespace std;
class A
{
public:
int t = 0;
A(){
cout << "constructed" << t<< endl;
}
A (A&& a) {
cout << "in move ctor, moving"<< a.t << endl;
}
~A() {
cout << "deleting"<< t << endl;
}
};
A f1 (A a)
{
a.t = 1;
std::cout << "f1: " << endl;
return a;
}
int main() {
A a = f1(A()) ;
printf("what is happeningn");
}
输出为
constructed0
in move ctor, moving0
f1:
in move ctor, moving1
in move ctor, moving0
deleting0
deleting1
deleting0
what is happening
deleting0
我无法理解的是为 f1 创建的临时对象(a.t=1 的对象(被销毁的阶段。
从输出中,我假设它在行A a = f1(A()) ;
的 and 处被销毁 虽然我认为它是在 f1 和 f1 中创建的,因此在调用 deleting0 之前退出函数时将被销毁。
我错过了什么?
所以经过一番研究,我有了答案。
下面是代码的反汇编(为了便于阅读,将移动构造函数更改为复制构造函数(:
int A::counter = 0;
A f1 (A a)
{
400a18: 55 push %rbp
400a19: 48 89 e5 mov %rsp,%rbp
400a1c: 48 83 ec 10 sub $0x10,%rsp
400a20: 48 89 7d f8 mov %rdi,-0x8(%rbp)
400a24: 48 89 75 f0 mov %rsi,-0x10(%rbp)
cout << __LINE__ << endl;
400a28: be 1d 00 00 00 mov $0x1d,%esi
400a2d: bf 80 13 60 00 mov $0x601380,%edi
400a32: e8 c1 fd ff ff callq 4007f8 <_ZNSolsEi@plt>
400a37: be 78 08 40 00 mov $0x400878,%esi
400a3c: 48 89 c7 mov %rax,%rdi
400a3f: e8 24 fe ff ff callq 400868 <_ZNSolsEPFRSoS_E@plt>
a.t = 1;
400a44: 48 8b 45 f0 mov -0x10(%rbp),%rax
400a48: c7 00 01 00 00 00 movl $0x1,(%rax)
std::cout << "f1: " << endl;
400a4e: be ce 0e 40 00 mov $0x400ece,%esi
400a53: bf 80 13 60 00 mov $0x601380,%edi
400a58: e8 fb fd ff ff callq 400858 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
400a5d: be 78 08 40 00 mov $0x400878,%esi
400a62: 48 89 c7 mov %rax,%rdi
400a65: e8 fe fd ff ff callq 400868 <_ZNSolsEPFRSoS_E@plt>
cout << __LINE__ << endl;
400a6a: be 20 00 00 00 mov $0x20,%esi
400a6f: bf 80 13 60 00 mov $0x601380,%edi
400a74: e8 7f fd ff ff callq 4007f8 <_ZNSolsEi@plt>
400a79: be 78 08 40 00 mov $0x400878,%esi
400a7e: 48 89 c7 mov %rax,%rdi
400a81: e8 e2 fd ff ff callq 400868 <_ZNSolsEPFRSoS_E@plt>
return a;
400a86: 48 8b 55 f0 mov -0x10(%rbp),%rdx
400a8a: 48 8b 45 f8 mov -0x8(%rbp),%rax
400a8e: 48 89 d6 mov %rdx,%rsi
400a91: 48 89 c7 mov %rax,%rdi
400a94: e8 dd 01 00 00 callq 400c76 <_ZN1AC1ERKS_>
}
400a99: 48 8b 45 f8 mov -0x8(%rbp),%rax
400a9d: c9 leaveq
400a9e: c3 retq
0000000000400a9f <main>:
int main() {
400a9f: 55 push %rbp
400aa0: 48 89 e5 mov %rsp,%rbp
400aa3: 53 push %rbx
400aa4: 48 83 ec 48 sub $0x48,%rsp
A a = f1(A()) ;
400aa8: 48 8d 45 e0 lea -0x20(%rbp),%rax
400aac: 48 89 c7 mov %rax,%rdi
400aaf: e8 2a 01 00 00 callq 400bde <_ZN1AC1Ev>
400ab4: 48 8d 55 e0 lea -0x20(%rbp),%rdx
400ab8: 48 8d 45 d0 lea -0x30(%rbp),%rax
400abc: 48 89 d6 mov %rdx,%rsi
400abf: 48 89 c7 mov %rax,%rdi
400ac2: e8 af 01 00 00 callq 400c76 <_ZN1AC1ERKS_>
400ac7: 48 8d 45 c0 lea -0x40(%rbp),%rax
400acb: 48 8d 55 d0 lea -0x30(%rbp),%rdx
400acf: 48 89 d6 mov %rdx,%rsi
400ad2: 48 89 c7 mov %rax,%rdi
400ad5: e8 3e ff ff ff callq 400a18 <_Z2f11A>
400ada: 48 8d 55 c0 lea -0x40(%rbp),%rdx
400ade: 48 8d 45 b0 lea -0x50(%rbp),%rax
400ae2: 48 89 d6 mov %rdx,%rsi
400ae5: 48 89 c7 mov %rax,%rdi
400ae8: e8 89 01 00 00 callq 400c76 <_ZN1AC1ERKS_>
400aed: 48 8d 45 c0 lea -0x40(%rbp),%rax
400af1: 48 89 c7 mov %rax,%rdi
400af4: e8 31 02 00 00 callq 400d2a <_ZN1AD1Ev>
400af9: 48 8d 45 d0 lea -0x30(%rbp),%rax
400afd: 48 89 c7 mov %rax,%rdi
400b00: e8 25 02 00 00 callq 400d2a <_ZN1AD1Ev>
400b05: 48 8d 45 e0 lea -0x20(%rbp),%rax
400b09: 48 89 c7 mov %rax,%rdi
400b0c: e8 19 02 00 00 callq 400d2a <_ZN1AD1Ev>
printf("what is happeningn");
400b11: bf d3 0e 40 00 mov $0x400ed3,%edi
400b16: e8 ed fc ff ff callq 400808 <puts@plt>
cout << __LINE__ << endl;
return a;
}
复制构造函数在重整过程后称为">ZN1AC1ERKS"。
正如我们所看到的,为 f1 创建的临时对象是在函数调用之前创建的,主要是在 f1 的作用域中创建的,而不是像我预期的那样。
含义如下:
为按值调用的函数创建的临时对象不是在函数范围内创建的,而是在称为函数的行中创建的,因此它们将在下一行执行之前以普通的先创建最后销毁方式被销毁。
相关文章:
- 在不复制临时对象的情况下延长其生存期
- 为什么当我们有常量引用时创建临时对象?
- 程序如何'remember'临时对象?
- 返回对临时对象的引用
- 防止临时对象文件访问 MSVC 中的磁盘
- 是否可以在C++中移动临时对象的属性?
- 通过引用传递临时对象
- 临时C++对象是否为左值?
- 临时对象:术语澄清
- 存储对(可能)临时对象的引用是否合法,只要引用不比对象存活?
- 临时对象有身份吗?
- 临时对象上的运算符重载
- 如何在没有 std::move 的情况下移动临时对象
- 临时对象在C++中是不可避免的吗?
- 编译错误:临时对象构造函数中缺少参数
- 为什么在按值返回时创建临时对象,而不是在按值传递给函数参数时创建临时对象
- 我试图创建临时对象的方式有错误吗
- 读取互斥对象范围之外的volatile变量,而不是std::atomic
- 按值函数创建范围的临时对象
- 范围内临时对象的生存期是多少?