C++ 取消引用指针的代价有多大?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/431469/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How expensive is it to dereference a pointer?
提问by tunnuz
How expensive is it to perform the dereference operation on a pointer?
对指针执行取消引用操作的代价有多大?
I can imagine that the memory transfer is somehow proportional to the object size, but I want to know how expensive the dereference operation part is.
我可以想象内存传输在某种程度上与对象大小成正比,但我想知道取消引用操作部分的开销有多大。
回答by CB Bailey
Dereferencing, when translated into machine code, can mean different things depending on what you do with the dereferenced object. Accessing a single member of a class through a pointer is typically cheap. For example if c is a pointer to an instance of class C
with an int
member n then something like this:
解引用,当翻译成机器代码时,可能意味着不同的东西,这取决于你对解引用的对象做了什么。通过指针访问类的单个成员通常很便宜。例如,如果 c 是指向class C
具有int
成员 n的实例的指针,则如下所示:
int n = c->n;
Might translate into one or two machine instructions and might load a register with a single memory access.
可能会转换为一两条机器指令,并且可能会通过一次内存访问加载一个寄存器。
On the other hand this implies making a complete copy of the object pointed to by c:
另一方面,这意味着制作 c 指向的对象的完整副本:
C d = *c;
The cost of this will depend on the size of C, but note that it is the copy that is the major expense and the 'dereference' part is really just 'using' the pointer address in the copy instructions.
这样做的成本将取决于 C 的大小,但请注意,主要费用是复制,而“取消引用”部分实际上只是“使用”复制指令中的指针地址。
Note that accessing members of large objects typically requires pointer offset calculation and memory access whether or not the object is a local object or not. Typically only very small objects are optimized to live only in registers.
请注意,无论对象是否为本地对象,访问大对象的成员通常都需要进行指针偏移计算和内存访问。通常只有非常小的对象被优化为仅存在于寄存器中。
If you are concerned about the cost of pointers over references then don't be. The difference between these are a language semantics difference and by the time the machine code is generated pointer and reference access look exactly the same.
如果您担心指针对引用的成本,那么请不要担心。它们之间的区别是语言语义上的差异,并且在机器代码生成时指针和引用访问看起来完全相同。
回答by Johannes Schaub - litb
It depends on what you do with the dereferenced pointer. A mere dereference operation does nothing in itself. It just gets an lvalue of type T
which represents your object, if your pointer is a T*
这取决于您如何处理取消引用的指针。单纯的取消引用操作本身没有任何作用。T
如果您的指针是一个代表您的对象的类型的左值T*
struct a {
int big[42];
};
void f(a * t) {
// does nothing. Only interesting for standard or compiler writers.
// it just binds the lvalue to a reference t1.
a & t1 = *t;
}
If you actually get the value out of that object denoted by the lvalue returned by the dereference operation, the compiler has to copy the data the object contains. For a simple POD, that is just a mere memcpy
:
如果您确实从解引用操作返回的左值所表示的对象中获取值,则编译器必须复制该对象包含的数据。对于一个简单的 POD,这仅仅是一个memcpy
:
a aGlobalA;
void f(a * t) {
// gets the value of of the object denoted by *t, copying it into aGlobalA
aGlobalA = *t;
}
My gcc port outputs this code for f:
我的 gcc 端口为 f 输出此代码:
sub , , 24 ; subtract stack-pointer, creating this frame
stw , , 20 ; save return address
add , struct a {
int big[42];
void operator=(a const&) { }
};
, ; copy pointer t into (src)
add , sub , , 8
add , , 8
jr
, aGlobalA ; load address of aGlobalA into (dst)
add , string name = first->next->next->next->name;
int age = first->next->next->next->age;
this is O(n)
, 168 ; put size (168 bytes) as 3rd argument
jal memcpy ; call memcpy
ldw , , 20 ; restore return address
add , , 24 ; add stack-pointer, destroying this frame
jr
Optimized machine code would use in-line code instead of a call to memcpy
, but that's really just an implementation detail. What is important is, that merely *t
isn't executing any code, but accessing the value of that object actually needs to copy it.
优化的机器代码将使用内嵌代码而不是调用memcpy
,但这实际上只是一个实现细节。重要的是,这只是*t
不执行任何代码,但访问该对象的值实际上需要复制它。
Would we have to do with a type having a user defined copy assignment operator, affairs are more complex:
我们是否必须处理具有用户定义的复制赋值运算符的类型,事务更复杂:
node* billy_block = first->next->next->next;
string name = billy_block->name;
int age = billy_block->age;
this is O(1)
The code for the same function f
now looks like:
相同函数的代码f
现在看起来像:
Hah. But it wasn't such a surprise, wasn't it? After all, the compiler is supposed to call our operator=
, and if it does nothing, the whole function also does nothing!
哈。但这并不意外,不是吗?毕竟,编译器应该调用我们的operator=
,如果它什么都不做,整个函数也什么都不做!
Conclusion
结论
I think the conclusion we can draw is, it all depends on how the returned value of operator*
is used. If we have just a pointer that we dereference, we see above that the code generated largely depends on the circumstances. I haven't showed how it behaves if we dereference a class type having overloaded operator*
. But essentially, it's just behaving like we saw with operator=
. All measurements were done with -O2
, so the compiler properly inlined calls :)
我想我们可以得出的结论是,这完全取决于返回值的operator*
使用方式。如果我们只有一个取消引用的指针,我们在上面看到生成的代码在很大程度上取决于环境。如果我们取消引用一个重载的类类型,我还没有展示它的行为operator*
。但本质上,它的行为就像我们在operator=
. 所有的测量都是用 完成的-O2
,所以编译器正确地内联了调用:)
回答by user52875
The most important factor in dereferencing pointers on ordinary systems is that you're likely to generate a cache miss. A random access in SDRAM memory costs tens of nanoseconds (e.g. 64). On gigaherz processors, this means that your processor is idling hundreds (or > thousand) of cycles, without being able of doing anything else in the meantime.
在普通系统上取消引用指针的最重要因素是您可能会产生缓存未命中。SDRAM 内存中的随机访问花费数十纳秒(例如 64)。在千兆处理器上,这意味着您的处理器空闲数百(或 > 千)个周期,同时无法做任何其他事情。
Only on SRAM based systems (which you'll only find in embedded software), or when your software is cache optimized, the factors discussed in the other posts come into play.
仅在基于 SRAM 的系统上(您只能在嵌入式软件中找到),或者当您的软件经过缓存优化时,其他帖子中讨论的因素才会发挥作用。
回答by Mehrdad Afshari
Dereferencing can be expensive mostly because it costs an instruction to fetch data from memory which might be far away and do not exhibit locality of reference. In that case, the processor should fetch data from non-cached memory and even hard disk (in case of a hard page fault).
取消引用可能很昂贵,主要是因为它需要花费一条指令从可能很远的内存中获取数据,并且不会表现出引用的局部性。在这种情况下,处理器应该从非缓存内存甚至硬盘中获取数据(在出现硬页面错误的情况下)。
回答by Michael Buen
Dereferencing(multiple) cost CPU cycles.
取消引用(多个)成本 CPU 周期。
Instead of writing:
而不是写:
##代码##
Write it as:
写成:
So your code will not "ask" each and every block just to get to the fourth block.
所以你的代码不会“询问”每个块只是为了到达第四个块。
Multiple dereferencing is like having a neighborhood who only knows a neighbor next to them.
多重解除引用就像一个邻居只知道他们旁边的邻居。
Imagine if you ask a person from the first block where does your friend Billy resides, he will tell you he doesn't know your friend, he'll tell you he only know the neighbor next to them, then he'll just tell you to ask his neighbor, then you'll ask his neighbor, he'll answer the same thing as the first block did, you keep asking until you arrive at your friend's block. Not very efficient
想象一下,如果你问第一个街区的一个人,你的朋友比利住在哪里,他会告诉你他不认识你的朋友,他会告诉你他只认识他们旁边的邻居,然后他只会告诉你问他的邻居,然后你会问他的邻居,他会回答和第一个街区一样的问题,你一直问,直到你到达你朋友的街区。效率不高
回答by EricSchaefer
The dereferencing of a pointer shouldn't be much more than copying an address to a (address)register. Thats all.
指针的解除引用不应该只是将地址复制到(地址)寄存器。就这样。