使用点运算符以多快的速度访问某些数据成本?例如:
struct A{
public:
A(): a(0){};
int a;
};
int main(){
A obj;
int b = 0;
cout << obj.a; // How much slower is this
cout << b; // Than this...?
return 0;
}
我知道我应该做基准测试,但这里有什么一般性的理解吗?
答案 0 :(得分:11)
让我们来看看这些被分解的代码:
cout << obj.a; // How much slower is this
0041161D mov esi,esp
0041161F mov eax,dword ptr [obj]
00411622 push eax
00411623 mov ecx,dword ptr [__imp_std::cout (41A34Ch)]
00411629 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (41A35Ch)]
0041162F cmp esi,esp
00411631 call @ILT+430(__RTC_CheckEsp) (4111B3h)
cout << b; // Than this...?
00411636 mov esi,esp
00411638 mov eax,dword ptr [b]
0041163B push eax
0041163C mov ecx,dword ptr [__imp_std::cout (41A34Ch)]
00411642 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (41A35Ch)]
00411648 cmp esi,esp
0041164A call @ILT+430(__RTC_CheckEsp) (4111B3h)
这是在没有优化的情况下编译的。即便如此,他们也需要同样的时间。 通过优化,代码更短,但仍然大致相同:
cout << obj.a; // How much slower is this
00401000 mov ecx,dword ptr [__imp_std::cout (40203Ch)]
00401006 push 0
00401008 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)]
cout << b; // Than this...?
0040100E mov ecx,dword ptr [__imp_std::cout (40203Ch)]
00401014 push 0
00401016 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)]
因此,对于您的代码段,性能是相同的。不同的编译器可能会出现细微的差异,但开销总是可以忽略不计或为0。
答案 1 :(得分:3)
在这种情况下,可能没有,因为struct A a
和int b
都应该优化为常量。
通常,.
表示必须计算偏移量,但通常(部分)计算可以在编译时完成。这不是你应该担心的事情。此外,如果您在堆栈上有多个变量而不是单个struct
,那么访问它们可能需要完全相同的偏移计算。
答案 2 :(得分:3)
基本上没有。完全没有。
这在很大程度上取决于您的情况 - 如果obj
是对当前不在缓存中的内存的引用,例如,基于大型节点的结构,那么它可能会花费您。否则,它几乎为零。编译器将确保在许多甚至大多数情况下,它实际上为零。
答案 3 :(得分:2)
在您的情况下,它没有任何区别,因为obj.a
可以在编译时解析,并且不会在运行时产生任何开销。您可能对this paper(pdf)感兴趣,它分析了调度虚函数调用的成本。
答案 4 :(得分:2)
使用member-access-operator时唯一的可能的运行时开销是在处理对基类的引用和调用虚函数时。但这确实只是 的可能性。通过此运算符访问成员永远不会有运行时开销。
答案 5 :(得分:1)
obj.a
,(&obj)->a
和*(int*)(&obj+0)
都相同。 offset
此处0
已添加到起始地址。要访问它。而我在编译时并不虚拟它的计算。因此没有与之相关的额外运行时成本。