c++中对象按值返回时地址为什么不同

icnyk63a  于 2023-08-09  发布在  其他
关注(0)|答案(1)|浏览(93)
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语句,在返回值期间也没有输出任何内容,这让我相信,如果没有发生复制或移动,那么一定发生了复制遗漏

1zmg4dgp

1zmg4dgp1#

复制省略不保证obj1obj2的地址相同。它只保证对象的构造将被省略。函数test()将在自己的作用域中构造obj1,该对象将用于在main()中直接初始化obj2,而无需调用任何复制/移动构造函数。但实际地址可能不同。
为了更好地理解这一点,让我们来看看生成的程序集(完整的输出在这里-Godbolt):

test():
    sub     rsp, 16
    lea     rax, [rbp-1]       // Address of obj1
    call    A::A()             // Constructor call for obj1
    mov     rsi, rax           // Printing the address of obj1
    call    std::basic_ostream::operator<<
    leave
    ret

main:
    sub     rsp, 16
    call    test()
    lea     rax, [rbp-1]       // Address of obj2
    mov     rsi, rax           // Printing the address of obj2
    call    std::basic_ostream::operator<<
    leave
    ret

字符串

栈地址分配

查看程序集,两个函数test()main()在启动时都将rsp(堆栈指针)减去16个字节。这通常是为了在堆栈上为局部变量和其他数据分配空间。在本例中,该数据分别包括我们的对象obj1obj2

对象构造

test()函数中,为obj1调用了A的构造函数。它的内存位置对应于[rbp-1],这是obj1的堆栈地址。类似地,在main中,即使由于复制省略而没有显式地为obj2调用构造函数,obj2的内存也被指定为[rbp-1]

地址输出

该程序分别输出obj1obj2的地址0x7ffd25c73fef0x7ffd25c7400f。我们可以看到这些地址不同,这与汇编输出的观察结果一致。每个函数都有自己的堆栈帧,所以即使obj1obj2rbp[rbp-1])的相对偏移量相同,它们在内存中的绝对地址也不同。
此外,查看两个地址之间的差异(十六进制的0x20),很明显,差异不仅仅是关于两个对象:其他因素,如函数调用机制、返回地址和可能的其他数据也会影响堆栈的布局。

相关问题