我很想知道通过指针访问数据成员和不通过指针访问数据成员的成本是多少,所以想到了这个测试:
#include <iostream>
struct X{
int a;
};
int main(){
X* xheap = new X();
std::cin >> xheap->a;
volatile int x = xheap->a;
X xstack;
std::cin >> xstack.a;
volatile int y = xstack.a;
}
生成的x86是:
int main(){
push rbx
sub rsp,20h
X* xheap = new X();
mov ecx,4
call qword ptr [__imp_operator new (013FCD3158h)]
mov rbx,rax
test rax,rax
je main+1Fh (013FCD125Fh)
xor eax,eax
mov dword ptr [rbx],eax
jmp main+21h (013FCD1261h)
xor ebx,ebx
std::cin >> xheap->a;
mov rcx,qword ptr [__imp_std::cin (013FCD3060h)]
mov rdx,rbx
call qword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (013FCD3070h)]
volatile int x = xheap->a;
mov eax,dword ptr [rbx]
X xstack;
std::cin >> xstack.a;
mov rcx,qword ptr [__imp_std::cin (013FCD3060h)]
mov dword ptr [x],eax
lea rdx,[xstack]
call qword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (013FCD3070h)]
volatile int y = xstack.a;
mov eax,dword ptr [xstack]
mov dword ptr [x],eax
看起来非指针访问需要两条指令,而通过指针访问需要一条指令。有人能告诉我为什么这是,这将需要更少的CPU周期来检索?
我试图理解指针在访问数据成员时是否会产生更多的CPU指令/周期,而不是非指针访问。
这个测试太糟糕了。
x
的完整分配如下:
mov eax,dword ptr [rbx]
mov dword ptr [x],eax
(编译器被允许对指令重新排序,并且已经这样做了)。
给y
赋值(编译器给了x
相同的地址)是
mov eax,dword ptr [xstack]
mov dword ptr [x],eax
几乎是相同的(读寄存器指向的内存,写到堆栈)。
第一个将更复杂,除了编译器在调用new
之后将xheap
保存在寄存器rbx
中,所以它不需要重新加载它。
在任何一种情况下,我都更担心这些访问是否错过了L1或L2缓存,而不是精确的指令。(处理器甚至不直接执行这些指令,它们在内部被转换成不同的指令集,并且可能以不同的顺序执行它们。)
通过指针访问而不是直接从堆栈访问,在最坏的情况下(获取指针)会花费额外的间接操作。这本身几乎总是无关紧要的;您需要查看整个算法,以及它如何与处理器的缓存和分支预测逻辑一起工作。