C ++中的指针与变速

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6919380/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 20:54:27  来源:igfitidea点击:

Pointer vs Variable speed in C++

c++performancevariablespointers

提问by Jerry

At a job interview I was asked the question "In C++ how do you access a variable faster, though the normal variable identifier or though a pointer". I must say I did not have a good technical answer to the question so I took a wild guess.

在一次求职面试中,我被问到“在 C++ 中,如何通过普通变量标识符或指针更快地访问变量”。我必须说我对这个问题没有很好的技术答案,所以我做了一个疯狂的猜测。

I said that access time will probably be that same as normal variable/identifier is a pointer to the memory address where the value is stored, just like a pointer. In other words, that in terms of speed they both have the same performance, and that pointers are only different because we can specify the memory address we want them to point to.

我说过访问时间可能与普通变量/标识符相同,它是指向存储值的内存地址的指针,就像指针一样。换句话说,就速度而言,它们都具有相同的性能,而指针只是不同,因为我们可以指定我们希望它们指向的内存地址。

The interviewer did not seem very convinced/satisfied with my answer (although he did not say anything, just carried on asking something else), therefore I though to come and ask SO'ers wether my answer was accurate, and if not why (from a theory and technical POV).

面试官似乎对我的回答不太相信/满意(虽然他什么都没说,只是继续问别的),所以我想来问问 SO'ers 我的回答是否准确,如果不是为什么(来自理论和技术 POV)。

采纳答案by LaC

A variable does not have to live in main memory. Depending on the circumstances, the compiler can store it in a register for all or part of its life, and accessing a register is much faster than accessing RAM.

变量不必存在于主内存中。根据情况,编译器可以将其全部或部分存储在寄存器中,并且访问寄存器比访问 RAM 快得多。

回答by paulsm4

When you access a "variable", you look up the address, and then fetch the value.

当您访问“变量”时,您会查找地址,然后获取值。

Remember - a pointer IS a variable. So actually, you:

请记住 - 指针是一个变量。所以实际上,你:

a) look up the address (of the pointer variable),

a) 查找(指针变量的)地址,

b) fetch the value (the address stored at that variable)

b) 获取值(存储在该变量中的地址)

... and then ...

... 进而 ...

c) fetch the value at the address pointed to.

c) 获取指向地址处的值。

So yes, accessing via "pointer" (rather than directly) DOES involve (a bit) of extra work and (slightly) longer time.

所以是的,通过“指针”(而不是直接)访问确实涉及(一点)额外的工作和(稍微)更长的时间。

Exactly the same thing occurs whether or not it's a pointer variable (C or C++) or a reference variable (C++ only).

无论它是指针变量(C 或 C++)还是引用变量(仅 C++),都会发生完全相同的事情。

But the difference is enormously small.

但差异非常小。

回答by dewtell

Let's ignore optimization for a moment, and just think about what the abstract machine has to do to reference a local variable vs. a variable through a (local) pointer. If we have local variables declared as:

让我们暂时忽略优化,只考虑抽象机必须做什么来引用局部变量与通过(局部)指针的变量。如果我们将局部变量声明为:

int i;
int *p;

when we reference the value of i, the unoptimized code has to go get the value that is (say) at 12 past the current stack pointer and load it into a register so we can work with it. Whereas when we reference *p, the same unoptimized code has to go get the value of p from 16 past the current stack pointer, load it into a register, and then go get the value that the register points to and load it into another register so we can work with it as before. The first part of the work is the same, but the pointer access conceptually involves an additional step that needs to be done before we can work with the value.

当我们引用 i 的值时,未优化的代码必须获取(比方说)当前堆栈指针之后 12 处的值并将其加载到寄存器中,以便我们可以使用它。而当我们引用 *p 时,相同的未优化代码必须从当前堆栈指针之后的 16 处获取 p 的值,将其加载到寄存器中,然后获取该寄存器指向的值并将其加载到另一个寄存器中所以我们可以像以前一样使用它。工作的第一部分是相同的,但指针访问在概念上涉及一个额外的步骤,在我们可以使用值之前需要完成该步骤。

That was, I think, the point of the interview question - to see if you understood the fundamental difference between the two types of access. You were thinking that the local variable access involved a kind of lookup, and it does - but the pointer access involves that very same type of lookup to get to the value of the pointer before we can start to go after the thing it is pointing to. In simple, unoptimized terms, the pointer access is going to be slower because of that extra step.

我认为,这就是面试问题的重点——看看你是否理解这两种访问方式之间的根本区别。您认为局部变量访问涉及一种查找,并且确实如此 - 但指针访问涉及到相同类型的查找以获取指针的值,然后我们才能开始追踪它所指向的对象. 用简单的、未优化的术语来说,由于这个额外的步骤,指针访问会变慢。

Now with optimization, it may happen that the two times are very close or identical. It is true that if other recent code has already used the value of p to reference another value, you may already find p in a register, so that the lookup of *p via p takes the same time as the lookup of i via the stack pointer. By the same token, though, if you have recently used the value of i, you may already find itin a register. And while the same might be true of the value of *p, the optimizer can only reuse its value from the register if it is sure that p hasn't changed in the mean time. It has no such problem reusing the value of i. In short, while accessing both values may take the same time under optimization, accessing the local variable will almost never be slower (except in really pathological cases), and may very well be faster. That makes it the correct answer to the interviewer's question.

现在通过优化,可能会发生两次非常接近或相同的情况。确实,如果其他最近的代码已经使用 p 的值来引用另一个值,那么您可能已经在寄存器中找到了 p,因此通过 p 查找 *p 与通过堆栈查找 i 花费的时间相同指针。但是,出于同样的原因,如果您最近使用过 i 的值,您可能已经找到在一个寄存器中。虽然 *p 的值可能也是如此,但优化器只能在确定 p 同时没有改变的情况下才能重用它从寄存器中的值。重用 i 的值没有这样的问题。简而言之,虽然在优化下访问两个值可能需要相同的时间,但访问局部变量几乎不会变慢(除非在真正的病态情况下),并且很可能会更快。这使它成为面试官问题的正确答案。

In the presence of memory hierarchies, the difference in time may get even more pronounced. Local variables are going to be located near each other on the stack, which means that you are very likely to find the address you need already in main memory and in the cache the first time you access it (unless it is the very first local variable you access in this routine). There is no such guarantee with the address the pointer points to. Unless it was recently accessed, you may need to wait for a cache miss, or even a page fault, to access the pointed-to address, which could make it slower by orders of magnitude vs. the local variable. No, that won't happen all the time - but it's a potential factor that could make a difference in some cases, and that too is something that could be brought up by a candidate in response to such a question.

在存在内存层次结构的情况下,时间差异可能会变得更加明显。局部变量将在堆栈上彼此靠近,这意味着您很可能在第一次访问它时在主内存和缓存中找到您需要的地址(除非它是第一个局部变量)您在此例程中访问)。指针指向的地址没有这样的保证。除非它最近被访问过,否则您可能需要等待缓存未命中,甚至页面错误,才能访问指向的地址,这可能会使它比局部变量慢几个数量级。不,这不会一直发生——但这是一个在某些情况下可能会产生影响的潜在因素,而且这也是候选人在回答此类问题时可能提出的问题。

Now what about the question other commenters have raised: how much does it matter? It's true, for a single access, the difference is going to be tiny in absolute terms, like a grain of sand. But you put enough grains of sand together and you get a beach. And though (to continue the metaphor) if you are looking for someone who can run quickly down a beach road, you don't want someone who will obsess about sweeping every grain of sand off the road before he or she can start running, you do want someone who will be aware when he or she is running through knee-deep dunes unnecessarily. Profilers won't always rescue you here - in these metaphorical terms, they are much better at recognizing a single big rock that you need to run around than noticing lots of little grains of sand that are bogging you down. So I would want people on my team who understand these issues at a fundamental level, even if they rarely go out of their way to use that knowledge. Don't stop writing clear code in the quest for microoptimization, but be aware of the kinds of things that can cost performance, especially when designing your data structures, and have a sense of whether you are getting good value for the price you are paying. That's why I think this was a reasonable interview question, to explore the candidate's understanding of these issues.

现在如何看待其他评论者提出的问题:这有多重要?的确,对于单次访问而言,绝对值差异很小,就像一粒沙子。但是你把足够多的沙粒放在一起,你就会得到一个海滩。虽然(继续这个比喻)如果你正在寻找一个可以在海滩路上快速奔跑的人,你不希望有人在他或她开始跑步之前会痴迷于清除路上的每一粒沙子,你确实需要有人在他或她不必要地穿过齐膝深的沙丘时意识到这一点。探查器不会总是在这里救你——用这些比喻术语来说,他们更擅长识别你需要跑来跑去的一块大石头,而不是注意到许多让你陷入困境的小沙粒。所以我希望我的团队中的人能够从根本上理解这些问题,即使他们很少特意使用这些知识。不要在追求微优化的过程中停止编写清晰的代码,但要注意可以降低性能的各种事情,尤其是在设计数据结构时,并了解您是否以所付出的代价获得了良好的价值. 这就是为什么我认为这是一个合理的面试问题,以探索候选人对这些问题的理解。并了解您所支付的价格是否物有所值。这就是为什么我认为这是一个合理的面试问题,以探索候选人对这些问题的理解。并了解您所支付的价格是否物有所值。这就是为什么我认为这是一个合理的面试问题,以探索候选人对这些问题的理解。

回答by Marcin Deptu?a

What paulsm4 and LaC said + a little asm:

paulsm4 和 LaC 说的 + 一点 asm:

    int y = 0;
mov         dword ptr [y],0  
    y = x;
mov         eax,dword ptr [x]   ; Fetch x to register
mov         dword ptr [y],eax   ; Store it to y
    y = *px;
mov         eax,dword ptr [px]  ; Fetch address of x 
mov         ecx,dword ptr [eax] ; Fetch x 
mov         dword ptr [y],ecx   ; Store it to y

Not that on the other hand it matters much, also this probably is harder to optimize (fe. you can't keep the value in cpu register, as the pointer just points to some place in memory). So optimized code for y = x; could look like this:

并不是说另一方面它很重要,这也可能更难优化(例如,您不能将值保留在 cpu 寄存器中,因为指针仅指向内存中的某个位置)。y = x 的优化代码;看起来像这样:

mov dword ptr [y], ebx- if we assume that local var x was stored in ebx

mov dword ptr [y], ebx- 如果我们假设本地 var x 存储在 ebx

回答by Adrian Regan

I think the interviewer was looking for you to mention the word register. As in, if you declare a variable as a register variable the compiler will do its utmost to ensure that it is stored in a register on the CPU.

我想面试官是在找你提到注册这个词。如在,如果您将变量声明为寄存器变量,编译器将尽最大努力确保它存储在 CPU 上的寄存器中。

A bit of chat around bus access and negotiation for other types of variables and pointers alike would have helped to frame it.

围绕总线访问和其他类型的变量和指针的协商进行一些讨论将有助于构建它。

回答by Abhinav

paulsm4 and LaC has already explained it nicely along with other members. I want to emphasize effect of paging when the pointer is pointing to something in heap which has been paged out.

=> Local variables are available either in the stack or in the register
=> while in case of pointer, the pointer may be pointing to an address which is not in cache and paging will certainly slow down the speed.

paulsm4 和 LaC 已经和其他成员一起很好地解释了它。我想强调当指针指向堆中已被分页的内容时分页的效果。

=> 局部变量在堆栈或寄存器中可用
=> 而在指针的情况下,指针可能指向不在缓存中的地址,分页肯定会减慢速度。

回答by MaximG

A variable holds a value of certain type, and accessing the variable means getting this value, from memory or from a register. When getting the value from memory we need to get it's address from somewhere - most of the time it has to be loaded into a register (sometimes it can be part of the load command itself, but this is quite rare).

变量保存某种类型的值,访问该变量意味着从内存或寄存器中获取该值。当从内存中获取值时,我们需要从某个地方获取它的地址——大多数时候它必须被加载到寄存器中(有时它可以是加载命令本身的一部分,但这种情况很少见)。

A pointer keeps an address of a value; this value has to be in memory, the pointer itself can be in memory or in a register.

一个指针保存一个值的地址;这个值必须在内存中,指针本身可以在内存或寄存器中。

I would expect that on average access via a pointer will be slower than accessing the value through a variable.

我希望通过指针访问平均比通过变量访问值要慢。

回答by nobar

Your analysis ignores the common scenario in which the pointer itself is a memory variable which must also be accessed.

您的分析忽略了指针本身是也必须访问的内存变量的常见情况。

There are many factors that affect the performance of software, but if you make certain simplifying assumptions about the variables involved (notably that they are not cached in any way), then each level of pointer indirection requires an additional memory access.

影响软件性能的因素有很多,但是如果您对所涉及的变量做出某些简化假设(特别是它们没有以任何方式缓存),那么每一级指针间接都需要额外的内存访问。

int a = 1234; // luggage combination
int *b = &a;
int **c = &b;
...
int e = a; // one memory access
int e = *b; // two memory accesses
int e = **c; // three memory accesses

So the short answer to "which is faster" is: ignoring compiler and processor optimizations which might be occurring, it is faster to access the variable directly.

所以对“哪个更快”的简短回答是:忽略可能发生的编译器和处理器优化,直接访问变量更快。

In a best-case scenario, where this code is executed repeatedly in a tight loop, the pointer value would likely be cached into a CPU register or at worst into the processor's L1 cache. In such a case, it is likely that a first-level pointer indirection is as fast or faster than accessing the variable directly since "directly" probably means via the "stack pointer" register (plus some offset). In both cases you are using a CPU register as a pointer to the value.

在最好的情况下,此代码在紧密循环中重复执行,指针值可能会缓存到 CPU 寄存器中,或者最坏的情况下会缓存到处理器的 L1 缓存中。在这种情况下,一级指针间接访问可能与直接访问变量一样快或更快,因为“直接”可能意味着通过“堆栈指针”寄存器(加上一些偏移量)。在这两种情况下,您都使用 CPU 寄存器作为指向该值的指针。

There are other scenarios that could affect this analysis, such as for global or static data where the variable's address is hard-coded into the instruction stream. In such a scenario, the answer may depend on the specifics of the processor involved.

还有其他情况可能会影响这种分析,例如对于变量地址被硬编码到指令流中的全局或静态数据。在这种情况下,答案可能取决于所涉及的处理器的具体情况。

回答by Carl

I think the key part of the question is "access a variable". To me, if a variable is in scope, why would you create a pointer to it (or a reference) to access it? Using a pointer or a reference would only make sense if the variable was in itself a data structure of some sort or if you were acessing it in some non-standard way (like interpreting an int as a float).

我认为问题的关键部分是“访问变量”。对我来说,如果变量在范围内,为什么要创建指向它的指针(或引用)来访问它?如果变量本身是某种类型的数据结构,或者如果您以某种非标准方式访问它(例如将 int 解释为浮点数),则使用指针或引用才有意义。

Using a pointer or a reference would be faster only in very specific circumstances. Under general circumstances, it seems to me that you would be trying to second guess the compiler as far as optimization is concerned and my experience tells me that unless you know what you're doing, that's a bad idea.

仅在非常特定的情况下,使用指针或引用会更快。在一般情况下,在我看来,就优化而言,您会尝试再次猜测编译器,而我的经验告诉我,除非您知道自己在做什么,否则这是一个坏主意。

It would even depend on the keyword. A const keyword might very well mean that the variable is totally optimized out at compile time. That is faster than a pointer. The register keyword does not guaranteethat the variable is stored in a register. So how do you know whether its faster or not? I think the answer is that it depends because there is no one size fits all answer.

它甚至取决于关键字。const 关键字很可能意味着该变量在编译时已完全优化。这比指针快。register 关键字不保证变量存储在寄存器中。那么你怎么知道它是否更快?我认为答案是视情况而定,因为没有一种适用于所有情况的答案。

回答by sandboxcoder

I think a better answer might be it depends on where the pointer is 'pointing to'. Note, a variable might already be in the cache. However a pointer might incur a fetch penalty. It's similar to a linked list vs Vector performance tradeoff. A Vector is cache friendly because all of your memory is contigious. However a linked list, since it contains pointers, might incur a cache penalty because the memory is potentially scattered all over the place

我认为更好的答案可能取决于指针“指向”的位置。请注意,一个变量可能已经在缓存中。但是,指针可能会导致获取损失。它类似于链表与 Vector 性能的权衡。Vector 是缓存友好的,因为您的所有内存都是连续的。然而,一个链表,因为它包含指针,可能会导致缓存惩罚,因为内存可能分散在所有地方