In strict C++ no object can be misaligned [basic.align]/1:
Object types have alignment requirements ([basic.fundamental], [basic.compound]) which place restrictions on the addresses at which an object of that type may be allocated.
So temporary or not, an object can not be misaligned. That being said misaligned object are used in low level codes, but such codes involve non standard c++ code (for example see Linux-kernel-doc/unaligned-memory-access.txt). You could try to pass a misaligned (non-existing) object to a function this way:
void f(const int& x);
void g(long x){
f(*reinterpret_cast<const int*>(reinterpret_cast<const unsigned char*>(&x)+1));
}
In such a code, which will cause undefined behavior, the coder clearly shows us he is not following the standard, the int
object passed to f
does not exist. So we are in an other realm and maybe in this realm one could call this int
object a temporary. Such code does exist in fact.
The first comment which talk about caches misses needs, in order to be understood, knowledge of the calling convention (how are argument passed at assembly level). On all ABI, references are passed by pointers to the refered object. So the referred object must be copied in memory. The paremeter x
of g
that initially lives in a register, will be copied to memory at a memory location that will be passed to f
. Below the AMD64 assembly code for g
produced by gcc:
//the argument x of g is in register rdi.
g(long):
sub rsp, 24
mov QWORD PTR [rsp+8], rdi //x is copied on to the stack
lea rdi, [rsp+9] //the misaligned pointer is stored in
//the first argument of f
call f(int const&)
add rsp, 24
ret
The argument passed to f
lives in memory, when latter its value will be accessed, that access may produces cache misses, and maybe more caches misses than if it where correctly aligned because the int object may be spread on two cache lines (see the rsp+9
). So passing argument by reference is not optimal if the object could have been otherwise be passed on a register (that is if the object is trivially copyable and small enough - 8 byte on window x86_64, 16 for Sys V abi for x86_64). And if the object is misaligned this is worst.
Below a mush better code is produced when f
take its argument by value:
void f(int x);
void g(long x){
f(*reinterpret_cast<const int*>(reinterpret_cast<const unsigned char*>(&x)+1));
}
And the generated assembly is perfect:
g(long):
sal rdi, 24 //no memory access just a right shift right and left shift
sar rdi, 32
jmp f(int) //tail call a ret from f will jump directly
//to g caller!