c++重复箭头运算符取消引用性能与点运算符
c++ repeated arrow operator dereferencing performance vs dot operator
箭头取消引用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...
}
因此,我的问题是,这两个版本之间的性能是否存在差异(即使很小),或者编译器是否足够聪明,可以使它们等效(即使不同的字段访问被它们之间的许多其他代码行中断,我在这里没有显示)。
箭头取消引用p->m是(*p).m 的语法糖
这通常不是真的,但在你提出问题的有限背景下是真的。
看起来可能涉及两个单独的内存查找操作——一个用于在堆上查找对象,另一个用于定位成员字段偏移。
一点也不。一个用于读取包含指针的参数或局部变量,另一个用于访问成员。但是,任何合理的优化器都会将指针保存在您显示的代码中的寄存器中,因此没有额外的访问权限。
但你的备用版本也有一个本地指针,所以无论如何都没有区别(至少在你询问的方向上):
classA &a = *ptr;
假设整个函数没有内联,或者由于其他原因,假设编译器不知道ptr
到底指向哪里,则&
必须使用指针,因此编译器可以推断出a
是*ptr
的别名是安全的,因此存在NO差异,或者编译器必须使a
成为*copy_of_ptr
的别名,因此使用&
的版本比复制ptr
的成本慢(而不是像您预期的那样快)。
即使不同的字段访问被许多行的它们之间的其他代码,我没有在这里显示
这会让你转向有趣的案例。如果干预代码可以更改ptr
,那么显然这两个版本的行为不同。但是,如果一个人能看到干预代码不能更改ptr
,而编译器却看不到:那么这两个版本在语义上是相等的,但编译器不知道这一点,编译器可能会为您试图通过创建引用手动优化的版本生成较慢的代码。
大多数(?all)编译器都在后台将引用实现为指针,因此我希望生成的程序集没有任何差异(除了初始化引用的可能副本之外,但我希望优化器甚至可以消除这一点)。
总的来说,这种微优化是不值得的。它总是最好集中在清晰和正确的代码上。当然不值得这样的优化,除非你已经测量到瓶颈在哪里。
- 取消引用运算符不能重载
- 为什么在我的函数类型后使用引用运算符 (&) 允许我修改它返回的值?
- 标准库类型的赋值运算符的引用限定符
- 使用运算符 [] 引用 std::vector 上最后一个元素时出现问题<>
- 移动赋值运算符;尝试引用已删除的函数.我该如何解决这个问题?
- 为什么我的运算符 + 重载尽管是通过引用传递的,但仍调用我的复制构造函数?
- C++编程:运算符重载中的引用如何工作?
- 重载运算符*以获取对另一个类的实例的引用
- 使用 scope 运算符 (::) 引用另一个文件中的类
- 对运算符=使用通用引用,而不是多个重载
- 如何重载下标运算符 [] 以引用 2d STL 数组?
- 未定义的引用和运算符 << vs me
- 为什么我不能在运算符=中使用引用类型?
- C++:对函子重载调用运算符的未定义引用
- 运算符重载C++类中的引用返回
- 如何在C++中使用 new 运算符创建对动态创建的数组的引用?
- 对模板运算符的未定义引用,其定义位于同一头文件中
- 为什么在通过引用返回运算符分配时取消引用'this'指针?
- 如果可能的话,C++总是更喜欢右值引用转换运算符而不是常量左值引用吗?
- 运算符++:引用与值返回和未使用的参数