5

使用指针时是否会影响性能?

避免使用指针会更好吗?如果是,在什么情况下?显然,它们与引用一起有助于减少数据复制。我假设如果指向的数据类型很小,那么对指针的需求就会更小。相反,最好通过指针传递大对象,因为指针的开销小于复制对象的开销。

我还想知道参数/参数以外区域的指针?

在这种性能上下文中,引用通常比指针更好吗?

我很感激我正在接近微优化的“肮脏”主题,但我正在编写一个非常关注延迟的应用程序。

4

6 回答 6

7

我知道性能可能很重要,但语义重要:快速和错误是无用的。

使用指针或引用具有语义含义,例如共享:

void foo(A& a) {
    a.a = 1;
    if (a.b != 0) { throw ... }
    a.b = 0;
}

在这种情况下a.b == 0,第一个字段a已更改,但第二个字段未更改。

此外,此类共享可能会产生潜在的混叠:

void foo(struct A a, struct A b);

void foo(struct A* a, struct A* b);

在第一种情况下,这两种结构必然是不同的,但在后一种情况下却不是。这种可能的别名可能会阻止优化。

首先关注语义。一旦你把它们做对了,你就可以在你的特定情况下调整和衡量效果。

于 2012-05-28T13:53:39.093 回答
4

在这种性能上下文中,引用通常比指针更好吗?

是的,尽可能使用引用,必要时使用指针。在性能方面,它们是相同的。

通常最好通过引用或指针传递大型结构以防止额外的复制,是的。

通过指针或引用访问变量或对象可能与直接访问它一样快。这种效率的原因在于微处理器的构造方式。在函数中声明的所有非静态变量和对象都存储在堆栈中,并且实际上是相对于堆栈指针进行寻址的。同样,在类中声明的所有非静态变量和对象都通过 C++ 中称为“this”的隐式指针访问。因此,我们可以得出结论,结构良好的 C++ 程序中的大多数变量实际上都是通过指针以一种或另一种方式访问​​的。因此,必须设计微处理器以使指针高效,这就是它们的本质。

虽然有一些缺点,但它们适用于指针和引用:

但是,使用指针和引用也有缺点。最重要的是,它需要一个额外的寄存器来保存指针或引用的值。寄存器是一种稀缺资源,尤其是在 32 位模式下。如果没有足够的寄存器,则每次使用时都必须从内存中加载指针,这会使程序变慢。另一个缺点是指针的值需要几个时钟周期才能访问指向的变量。

这里是来源。如果你问这个问题,我想你会发现它是一本好书。

让我们看一些代码:

   int x = 0;
00412E0E  mov         dword ptr [x],0 
   foo(x);
00412E15  lea         eax,[x] 
00412E18  push        eax  
00412E19  call        foo (4111C2h) 
00412E1E  add         esp,4 
   foo(&x);
00412E21  lea         eax,[x] 
00412E24  push        eax  
00412E25  call        foo (4111BDh) 
00412E2A  add         esp,4 

调用函数时没有区别。

void foo (int& x)
{
00411370  push        ebp  
00411371  mov         ebp,esp 
00411373  sub         esp,0C0h 
00411379  push        ebx  
0041137A  push        esi  
0041137B  push        edi  
0041137C  lea         edi,[ebp-0C0h] 
00411382  mov         ecx,30h 
00411387  mov         eax,0CCCCCCCCh 
0041138C  rep stos    dword ptr es:[edi] 
   x = 3;
0041138E  mov         eax,dword ptr [x] 
00411391  mov         dword ptr [eax],3 
}

void foo (int* x)
{
004117A0  push        ebp  
004117A1  mov         ebp,esp 
004117A3  sub         esp,0C0h 
004117A9  push        ebx  
004117AA  push        esi  
004117AB  push        edi  
004117AC  lea         edi,[ebp-0C0h] 
004117B2  mov         ecx,30h 
004117B7  mov         eax,0CCCCCCCCh 
004117BC  rep stos    dword ptr es:[edi] 
   *x = 3;
004117BE  mov         eax,dword ptr [x] 
004117C1  mov         dword ptr [eax],3 
}

功能内部没有区别。

于 2012-05-28T13:36:55.990 回答
1

这取决于指针指向的位置。如果在堆栈上分配对象并且您在许多情况下传递指针参数将比指向堆上对象的指针更快。如果您传递的对象在大多数机会已经被 CPU 缓存之前在函数中被积极使用,那么性能将大致相同。

关于复制... 大多数编译器将使用 CPU 寄存器来传递指针,这是 CPU 中可用的最快内存。但是,如果您将作为值传递,编译器将需要复制整个对象并调用 ctor / dtor。

所以我的建议是尝试将东西放在堆栈上并通过指针/引用传递。

很难说性能不是恒定的,并且可能会在不同的硬件/操作系统/编译器上发生变化,所以我的建议是使用分析器工具对代码进行分析,以分析缓存未命中、内存碎片、cpu 使用率等问题。

http://en.wikipedia.org/wiki/VTune

http://developer.amd.com/tools/CodeAnalyst/Pages/default.aspx

于 2012-05-28T14:08:27.287 回答
1

通过指针访问数据比直接访问数据要慢一些,但取消引用操作非常快,这通常没什么大不了的,除非您正在执行一些非常具体的重复数字运算任务。

关于传递大对象和小对象的指针,您是完全正确的。例如,int* 和 int 的大小可能相同,具体取决于实现。

引用和指针在性能方面通常是相同的。但是,如果您习惯使用 const Foo& 而不是 Foo*,编译器通常可以更好地优化您的代码。

于 2012-05-28T13:36:35.990 回答
1

您对基于堆的对象的最大问题是,当您需要它们时,它们通常不会放在一起,这意味着您需要更多时间将这些对象读入 CPU 缓存以处理它们(即,如果您有 10 个对象您需要使用的,如果它们都是连续分配的,则单个内存读取将一次性将它们全部推入缓存,如果它们分散在整个堆中,则需要对它们中的每一个进行读取)。

公平地说,这适用于所有堆系统,包括垃圾收集系统,即使在垃圾压缩之后也是如此。答案(显然)是将这些对象一起分配,或者提供一个带有空闲空间的缓冲区,以便随着时间的推移将它们分配到其中。

指针的另一个问题是您需要间接访问指针对象。如果你有一个对象数组,你很好——它们通常是连续的。但是,如果您有一个指针数组,则必须读取这些指针才能找出读取对象的位置。

现在,指针也可以很快——如果你使用指针算法来访问你的连续对象(因为你只需要读取一个指针来找出所有对象的位置)。

所以简而言之,问题不在于指针本身,而在于你如何组织它们指向的数据。

于 2012-05-28T13:40:14.783 回答
-2

使用指针对性能没有影响。指针的使用非常快。在大多数(所有?)专业项目中,指针被用作常用工具。它们用于在任何地方构建列表、队列、地图、树、数据库。习惯他们!!!

于 2012-05-28T13:37:14.527 回答