什么是临时错位
What is a misaligned temporary?
当谈到const T&
时,这个答案提到它可能会因为"临时性不一致"而变慢。什么是未对齐的临时性,我在代码中会在哪里遇到它?
答案是:
由于临时性不一致和间接成本,
const T&
的获取速度可能较慢。
然后两条评论:
即使没有由于错位而导致的性能损失,引用被实现为指针这一事实也需要将值存储在主存储器中,主存储器的速度可能比通过寄存器慢一个(一级缓存(到十个(页面故障(数量级。
这并不能解释什么是未对齐的临时地址。指针可以指向未对齐的地址,但这不能解释什么为未对齐的暂时地址。下一条注释未处理:
为什么临时仓库会不对齐?除非您偏离了未定义的行为,否则C++中的所有对象都是按定义对齐的。
在严格的C++中,任何对象都不能错位[basic.align]/1:
对象类型具有对齐要求(〔basic.basic〕,〔basic.compound〕(,这些要求对可以分配该类型对象的地址进行了限制。
因此,无论是否临时,对象都不能错位。也就是说,未对齐的对象在低级别代码中使用,但此类代码涉及非标准c++代码(例如,请参阅Linux内核doc/unlined memory access.txt(。您可以尝试通过以下方式将未对齐(不存在(的对象传递给函数:
void f(const int& x);
void g(long x){
f(*reinterpret_cast<const int*>(reinterpret_cast<const unsigned char*>(&x)+1));
}
在这样一个会导致未定义行为的代码中,编码器清楚地向我们表明他没有遵循标准,传递给f
的int
对象不存在。所以我们在另一个领域,也许在这个领域可以将这个int
对象称为临时对象。事实上确实存在这样的代码。
关于缓存未命中的第一个注释需要了解调用约定(如何在程序集级别传递参数(才能被理解。在所有ABI上,引用都是通过指向被引用对象的指针传递的。因此,引用的对象必须复制到内存中。最初存在于寄存器中的g
的奇偶校验器x
将被复制到将被传递给f
的存储器位置处的存储器中。以下是gcc生产的g
的AMD64汇编代码:
//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
传递给f
的参数存在于内存中,当后者的值将被访问时,该访问可能会产生缓存未命中,并且可能会产生比正确对齐时更多的缓存未命中(因为int对象可能分布在两条缓存线上((请参阅rsp+9
(。因此,如果对象本来可以在寄存器上传递,则通过引用传递参数不是最佳的(也就是说,如果对象是普通的可复制对象,并且足够小——在窗口x86_64上为8字节,对于x86_64的Sys V abi为16字节(。如果物体错位,这是最糟糕的。
下面是当f
按值取其参数时生成的更好的代码:
void f(int x);
void g(long x){
f(*reinterpret_cast<const int*>(reinterpret_cast<const unsigned char*>(&x)+1));
}
生成的组件是完美的:
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!
没有理由期望临时工失调。由于间接性,对引用效率低于值的担忧是有效的,也许偶尔你甚至会发现对未对齐值的引用,但未对齐的临时引用是极不可能的。
注意:在这个问题发布之前,在网络上搜索"c++"错位临时"只有一个结果,这导致了404错误页面。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 警告处理为错误这里有什么问题
- 什么时候调用组成单元对象的析构函数
- #定义c-预处理器常量..我做错了什么
- 努力将整数转换为链表。不知道我在这里做错了什么
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 什么时候在C++中返回常量引用是个好主意
- 当在同一名称空间中有两个具有相同签名的函数时,会发生什么
- C++避免重复声明的语法是什么
- c++库的公共头文件中应该包含什么
- 问题:什么是QAbstractItemView::NoEditTriggers的反面
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- ifstream什么都没读
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- C++从另一个类访问公共静态向量的正确方法是什么
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- 我应该使用什么来代替void作为变体中的替代类型之一
- 什么是临时错位