4

This answer when talking about const T& mentions that it can be slower due to "misaligned temporaries". What is a misaligned temporary and where would I encounter it in code?

The answer states:

Taking const T& could be slower due to misaligned temporaries and the cost of indirection.

Then the two comments:

Even if there are no performance penalties due to misalignment, the mere fact that a reference is implemented as a pointer requires the value to be stored in main memory, which can be between one (L1 cache) and ten (page fault) orders of magnitude slower than passing by register.

This does not explain what a misaligned temporary is. A pointer can point to a misaligned address, but that does not explain what a misaligned temporary is. The next comment goes unaddressed:

Why would temporaries be unaligned? Unless you stray into undefined behavior, all objects in C++ are by definition aligned.

2 Answers2

2

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!
Oliv
  • 17,610
  • 1
  • 29
  • 72
  • Also may want to discuss [strict aliasing](https://stackoverflow.com/a/51228315/1708801), I discuss unaligned access in my reference article. – Shafik Yaghmour Oct 28 '18 at 15:11
1

There is no reason to expect temporaries to be misaligned. The concern about references being less efficient than values due to indirection is valid, and perhaps occasionally you might even find a reference to a misaligned value, but a misaligned temporary is exceedingly unlikely.

Note: before this question was posted, a web search for 'c++ "misaligned temporary' had only a single result, which led to a 404 error page.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436