取消引用p->m
的箭头是(*p).m
的语法糖,看起来可能涉及两个独立的内存查找操作 - 一个用于查找堆上的对象,另一个用于查找成员字段偏移量。
这让我怀疑这两个代码片段之间是否存在任何性能差异。假设classA
有30多个不同类型的不同字段需要以各种顺序访问(不一定是连续或连续):
版本1:
void func(classA* ptr)
{
std::string s = ptr->field1;
int i = ptr->field2;
float f = ptr->field3;
// etc...
}
版本2:
void func(classA* ptr)
{
classA &a = *ptr;
std::string s = a.field1;
int i = a.field2;
float f = a.field3;
// etc...
}
所以我的问题是这两个版本之间的性能是否存在差异(即使非常轻微),或者编译器是否足够聪明以使它们等效(即使不同的字段访问被许多行中断)在他们之间的其他代码,我没有在这里显示。)
答案 0 :(得分:3)
取消引用p-> m的箭头是(* p).m
的语法糖
这通常不正确,但在您提出的有限背景下确实如此。
看起来可能涉及两个单独的内存查找 操作 - 一个用于查找堆上的对象,另一个用于查找堆上的对象 找到成员字段偏移量。
完全没有。它是一个读取保持指针的参数或局部变量,第二个是访问成员。但是任何合理的优化器都会将指针保存在您显示的代码中的寄存器中,因此无需额外访问。
但你的备用版本也有一个本地指针,所以无论如何都没有区别(至少在你问的方向):
classA &a = *ptr;
假设整个函数没有内联或由于某些其他原因而假设编译器并不确切知道ptr
指向的位置,&
必须使用指针,因此编译器可以推导出它a
是#{1}}的别名是安全的,因此存在 NO 差异,或者编译器必须使*ptr
为别名a
所以使用*copy_of_ptr
的版本比复制&
的费用慢(不像您预期的那么快)。
即使不同的字段访问被许多行中断 他们之间的其他代码,我没有在这里显示
这会让你走向有趣的案例。如果干预代码可以改变ptr
那么显然两个版本的行为不同。但是,如果一个人可以看到干预代码不能改变ptr
而编译器无法看到:那么两个版本在语义上是相等的,但是编译器没有知道这一点,并且编译器可能会为您尝试通过创建引用进行手动优化的版本生成较慢代码。
答案 1 :(得分:2)
大多数(?all)编译器将引用实现为引擎,因此我预计生成的程序集没有区别(除了可能的副本以初始化引用 - 但我希望优化器甚至可以消除它)。
一般来说,这种微优化并不值得。始终倾向于专注于清晰正确的代码。在你测量出瓶颈所在的位置之前,当然不值得这种优化。