class A {
public:
A(){}
};
A test() {
A obj1;
cout<<&obj1<<endl;
return obj1;
}
int main()
{
A obj2 = test();
cout<<&obj2<<endl;
return 0;
}
字符串
使用g++ -std=c++20编译
地址obj 1 = 0x 7 ff 7 bb 6 b72 e8和地址obj 2 = 0x 7 ff 7 bb 6 b7348,
我正在学习什么是复制省略,并测试了上面的代码。为什么地址不一样?我原以为会发生抄写遗漏。如果我返回一个向量,地址保持不变
我还创建了复制和移动构造函数和赋值语句,并添加了cout语句,在返回值期间也没有输出任何内容,这让我相信,如果没有发生复制或移动,那么一定发生了复制遗漏
1条答案
按热度按时间1zmg4dgp1#
复制省略不保证
obj1
和obj2
的地址相同。它只保证对象的构造将被省略。函数test()
将在自己的作用域中构造obj1
,该对象将用于在main()
中直接初始化obj2
,而无需调用任何复制/移动构造函数。但实际地址可能不同。为了更好地理解这一点,让我们来看看生成的程序集(完整的输出在这里-Godbolt):
字符串
栈地址分配
查看程序集,两个函数
test()
和main()
在启动时都将rsp
(堆栈指针)减去16个字节。这通常是为了在堆栈上为局部变量和其他数据分配空间。在本例中,该数据分别包括我们的对象obj1
和obj2
。对象构造
在
test()
函数中,为obj1
调用了A
的构造函数。它的内存位置对应于[rbp-1]
,这是obj1
的堆栈地址。类似地,在main中,即使由于复制省略而没有显式地为obj2
调用构造函数,obj2
的内存也被指定为[rbp-1]
。地址输出
该程序分别输出
obj1
和obj2
的地址0x7ffd25c73fef
和0x7ffd25c7400f
。我们可以看到这些地址不同,这与汇编输出的观察结果一致。每个函数都有自己的堆栈帧,所以即使obj1
和obj2
从rbp
([rbp-1]
)的相对偏移量相同,它们在内存中的绝对地址也不同。此外,查看两个地址之间的差异(十六进制的
0x20
),很明显,差异不仅仅是关于两个对象:其他因素,如函数调用机制、返回地址和可能的其他数据也会影响堆栈的布局。