In C++ with pass-by-value, the caller constructs the copy, which the callee uses. In x64 ABI, some arguments are passed in registers. Registers don't have addresses.
So suppose I have the following class:
class Self_Pointer
{
Self_Pointer* self;
Self_Pointer(const Self_Pointer& obj) : self(this) {}
}
When passed as an argument, it takes a pointer to itself. And now I have this function:
f(Self_Pointer x) {}
f()
takes a Self_Pointer by value, passed in a register by the calling convention. A caller of f()
would have to create a copy in a register. Thus, the caller would run the constructor on a Self_Pointer located in a register. However, registers don't have addresses, so it would be impossible to run the constructor. How is this dilemma resolved?
[Edit: fixed the class's ctor to a copy ctor, as per Steve Jessop's answer.]
Firstly, a copy of a Self_Pointer
doesn't point to itself. It points to the original because the compiler-generated copy constructor copies the value of self
from the original to the copy.
So, when you pass an object by copy to f
, in fact x
doesn't point to itself.
If you fixed that by writing a suitable copy constructor for Self_Pointer
, then the implementation would be required to ensure that x
has an address. If that means not passing it in registers, then it would not be passed in registers. Generally ABIs do not pass structures in registers unless they are of aggregate type, which your example is not since it has a user-defined constructor.
For another example, consider:
void foo(int i) {
std::cout << &i << '\n';
}
Again, the implementation is required to arrange that i
has an address. If it is passed in a register (and if like x64 registers don't have addresses on that particular hardware) then the function foo
must spill i
to the stack. Then it will have an address like any other stack variable.