此answer在谈论const T&
时提到,由于“临时人员错位”,它会变慢。什么是未对齐的临时文件,我在代码中会在哪里遇到?
答案指出:
由于临时人员的位置不一致和间接调用的成本,采取
const T&
的速度可能会变慢。
然后有两个评论:
即使没有由于未对齐而导致的性能损失,仅将引用实现为指针这一事实也要求将值存储在主存储器中,该值可以介于1(L1缓存)和10(页面错误)之间。比通过寄存器慢几个数量级。
这不能解释什么是未对齐的临时文件。指针可以指向未对齐的地址,但这不能解释什么是未对齐的临时地址。下一条评论未解决:
为什么临时人员会不结盟?除非您误入未定义的行为,否则C ++中的所有对象都是按照定义对齐的。
答案 0 :(得分:2)
在严格的C ++中,无法对齐对象[basic.align]/1:
对象类型具有对齐要求([basic.fundamental],[basic.compound]),这些条件对可以分配该类型的对象的地址施加了限制。
无论是否临时,都不能使对象未对齐。就是说,未对齐的对象用于低级代码,但此类代码涉及非标准的c ++代码(例如,参见Linux-kernel-doc/unaligned-memory-access.txt)。您可以尝试通过以下方式将未对齐(不存在)的对象传递给函数:
void f(const int& x);
void g(long x){
f(*reinterpret_cast<const int*>(reinterpret_cast<const unsigned char*>(&x)+1));
}
在这样的代码中,这将导致未定义的行为,编码人员清楚地表明我们没有遵循该标准,传递给int
的{{1}}对象不存在。因此,我们在另一个领域中,也许在这个领域中,可以将这个f
对象称为临时对象。这样的代码确实存在。
第一个谈论缓存的注释未满足需要,以便理解调用约定的知识(如何在汇编级传递参数)。在所有ABI上,引用都是通过指向所引用对象的指针传递的。因此,必须将引用的对象复制到内存中。最初位于寄存器中的int
的参数x
将被复制到内存中的某个存储位置,然后将其传递给g
。在gcc生成的f
的AMD64汇编代码下面:
g
传递给//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
的参数保存在内存中,当后者的值将被访问时,该访问可能会产生高速缓存未命中,并且与正确对齐的情况相比,高速缓存未命中可能会更多,因为int对象可能散布在两条缓存行(请参阅f
)。因此,如果对象可以通过其他方式传递到寄存器中(也就是说,如果对象是可微复制的并且足够小-窗口x86_64上为8字节,对于x86_64则为Sys V abi,则按引用传递参数不是最佳选择)。如果物体未对准,这是最糟糕的情况。
当rsp+9
以值作为参数时,会产生更好的代码:
f
生成的程序集是完美的:
void f(int x);
void g(long x){
f(*reinterpret_cast<const int*>(reinterpret_cast<const unsigned char*>(&x)+1));
}
答案 1 :(得分:1)
没有理由期望临时人员会错位。担心由于间接引用导致引用效率不及值的担心是正确的,也许有时您甚至可能找到对未对齐值的引用,但临时对齐的可能性极小。
注意:在发布此问题之前,网络搜索“ c ++“临时对齐的””只有一个结果,从而导致404错误页面。