在带有pass-by-value的C ++中,调用者构造被调用者使用的副本。在x64 ABI中,一些参数在寄存器中传递。寄存器没有地址。
假设我有以下课程:
class Self_Pointer
{
Self_Pointer* self;
Self_Pointer(const Self_Pointer& obj) : self(this) {}
}
作为参数传递时,它会指向自身。现在我有了这个功能:
f(Self_Pointer x) {}
f()
按值获取Self_Pointer,由调用约定传入寄存器。调用者f()
必须在寄存器中创建副本。因此,调用者将在位于寄存器中的Self_Pointer上运行构造函数。但是,寄存器没有地址,因此无法运行构造函数。这种困境是如何解决的?
[编辑:按照Steve Jessop的回答,将班级的ctor修改为副本ctor。]
答案 0 :(得分:2)
使用寄存器(或堆栈,用于参数传递)是特定编译器的实现细节。为了获得传递给函数的地址,编译器将寄存器的值复制到内存中的临时位置(通常在堆栈中),将其地址传递到需要的位置,然后从中加载数据。如果需要,临时位置回到同一个寄存器。
答案 1 :(得分:2)
首先,Self_Pointer
的副本并不指向自己。它指向原始文件,因为编译器生成的复制构造函数将self
的值从原始副本复制到副本。
因此,当您将副本传递给f
时,实际上x
并不指向自己。
如果通过为Self_Pointer
编写合适的复制构造函数来解决此问题,则需要实现以确保x
具有地址。如果这意味着不将它传递给寄存器,那么它就不会在寄存器中传递。通常ABI不会在寄存器中传递结构,除非它们是聚合类型,因为它有一个用户定义的构造函数,所以你的例子不是。
再举一个例子,考虑一下:
void foo(int i) {
std::cout << &i << '\n';
}
同样,需要实施以安排i
具有地址。如果它在寄存器中传递(并且如果x64寄存器在该特定硬件上没有地址),则函数foo
必须将i
溢出到堆栈。然后它将有一个像任何其他堆栈变量一样的地址。
答案 2 :(得分:0)
不,你不能。你得到的地址总是RAM的虚拟地址。您无法直接在C ++中访问寄存器的地址。