C++ C++;哪个功能更快?重复分配或重复创造

C++ C++;哪个功能更快?重复分配或重复创造,c++,performance,function,variables,static,C++,Performance,Function,Variables,Static,我认为下面的图片可以很好地解释这一点,但区别主要在于每次调用都会分配一个静态变量,或者每次调用都会创建一个普通变量(?) 谢谢你的见解 编辑:我添加了一个快速程序。我不知道这有多无意义,但它们同时执行。我觉得这不是一个好的测试。我想这不值得担心 #include <iostream> #include <time.h> using namespace std; #define ONE_BILLION 1000000000 #define HUNDRED_MILLIO

我认为下面的图片可以很好地解释这一点,但区别主要在于每次调用都会分配一个静态变量,或者每次调用都会创建一个普通变量(?)

谢谢你的见解

编辑:我添加了一个快速程序。我不知道这有多无意义,但它们同时执行。我觉得这不是一个好的测试。我想这不值得担心

#include <iostream>
#include <time.h>

using namespace std;

#define ONE_BILLION 1000000000
#define HUNDRED_MILLION 100000000


long long functionStatic(int arg)
{
    static long long randNum;
    srand(time(NULL));
    randNum = rand() % 20;
    return arg + randNum;
}

long long functionLocal(int arg)
{
    long long randNum;
    srand(time(NULL));
    randNum = rand() % 20;
    return arg + randNum;
}


int main()
{
    long long timeStart;
    long long duration;
    long long randNum;
    long long accum = 0;

    timeStart = clock();


    for (int i = 0; i < HUNDRED_MILLION; i++)
    {
        srand(time(NULL));
        randNum = rand() % 50;
        accum += functionStatic(randNum);
    }

    cout << "Time for static variable function: " << clock() - timeStart << " milliseconds" << endl << endl;
    timeStart = clock();

    for (int i = 0; i < HUNDRED_MILLION; i++)
    {
        srand(time(NULL));
        randNum = rand() % 50;
        accum += functionLocal(randNum);
    }

    cout << "Time for local variable function: " << clock() - timeStart << " milliseconds" << endl;

    return 0;
}
#包括
#包括
使用名称空间std;
#定义十亿亿欧元
#定义亿欧元100000000
长函数静态(int arg)
{
静态长随机数;
srand(时间(空));
randNum=rand()%20;
返回arg+randNum;
}
长函数本地(int arg)
{
朗朗纳姆;
srand(时间(空));
randNum=rand()%20;
返回arg+randNum;
}
int main()
{
长时间启动;
持续时间长;
朗朗纳姆;
长累计=0;
timeStart=clock();
对于(int i=0;i<1亿;i++)
{
srand(时间(空));
randNum=rand()%50;
accum+=函数静态(随机数);
}

cout对于使用-O2构建的g++4.9.2,使用静态会有轻微的损失,因为它不会优化存储

// static int a;
// a = 2;
// a += Someclass::number + Someclass::number2;
mov    0x0(%rip),%eax      # Get Someclass::number
add    0x0(%rip),%eax      # Add Someclass::number2
add    $0x2,%eax           # Add 2
mov    %eax,0x0(%rip)      # Store result in a
retq                       # return
a
不是静态的版本少了一条指令:

// int a = 2;
// a += Someclass::number + Someclass::number2;
mov    0x0(%rip),%eax      # Get Someclass::number  
add    0x0(%rip),%eax      # Add Someclass::number2
add    $0x2,%eax           # Add 2
retq                       # Return
但是,对于clang 3.6.0,结果是相同的:

// static int a;
// a = 2;
// a += Someclass::number + Someclass::number2;
mov    0x0(%rip),%eax    
mov    0x0(%rip),%ecx    
lea    0x2(%rax,%rcx,1),%eax
retq


// int a = 2;
// a += Someclass::number + Someclass::number2;
mov    0x0(%rip),%eax    
mov    0x0(%rip),%ecx    
lea    0x2(%rax,%rcx,1),%eax
retq

让我们看看这两种情况都发生了什么

情况1:-
int a
作为局部变量

在这种情况下,编译器可以进行优化,也就是说,它可以将其放入寄存器或缓存中。因此,如果函数被多次调用,显然,这一函数将比
静态
变量稍有优势

案例2:-使其成为
static int a

在这种情况下,一旦变量初始化,它将被分配到程序的静态数据区,并一直保存到程序退出。 编译器也拒绝对此函数执行任何优化,因此每次调用函数时,都会从主存中提取一个
,然后进行修改,然后再次写入主存,这将转化为比第一种情况下的汇编指令数量更多


最终结论:-第一种情况可能比第二种情况好。但情况可能并非总是这样,因为有更多的因素会影响性能,如其他人提到的编译器、CPU、底层硬件平台或操作系统。

除了“视情况而定”之外,没有真正的答案

您的问题实际上属于“过早优化”的范畴。您没有提到“测试”或“分析”之类的概念,而是单独担心特定代码构造的性能,这一事实支持这种特性

使用静态方法a(一次性)在第一次调用函数之前的某个时间创建该静态,并每次重新分配。在运行时,这意味着访问和/或修改内存中该位置的最新值。这可能意味着,根据调用函数的频率和CPU的工作方式,访问处理器缓存,返回RAM(比缓存慢),或从交换空间检索该位置的数据(如果在硬盘驱动器上交换空间,则比内存慢得多)。因此,性能取决于主机系统的内存体系结构,并且可能会有一些变化

使用自动变量通常意味着分配和初始化堆栈空间的某个区域。该区域的性能同样取决于主机系统的内存体系结构,但不太可能像静态变量那样可变

编译器还可以完全优化自动变量的使用,将其放入机器寄存器或其他技巧以提高代码的性能。当涉及静态变量时,编译器进行此类优化的空间较小

然而,最终,差异可能是微不足道的——即使在频繁调用的代码中也是如此。频繁调用的函数中的其他东西——算法等——可能对性能的影响比担心变量应该是静态的还是自动的更大


我建议首先为可读性和可维护性对函数进行编码。这意味着,在实践中,可能不会使变量成为静态的-因为这意味着有更多定义的路径供数据进出函数,因此更难理解。然后在实际用例中测试代码的性能。如果发现了某些性能问题,请通过探查器运行它,并找出真正的瓶颈(如果有的话)在哪里。更有可能的是,代码中的变量
a
甚至不会与任何瓶颈有关。或者,如果是,则是低阶效应-其他因素将占主导地位。因为在现实世界中,driv影响程序性能的因素通常是代码不同部分之间的交互,而不是一个变量属性的微小调整所影响的因素。

有一点尚未真正涉及,我认为这与您的问题有关。在您的示例中,您碰巧使用了int。因为您使用了int(适用于任何普通类型),静态初始化可以以特别有效的方式完成。但是,在函数中创建静态变量可能会非常昂贵:

struct A {
  A(double y) : z(y) { }

  double z;
 };

A func(double x) {
  static A a(0);
  a.z += x;
  return a;
}
编译为(使用-O2):

发生了什么事?像a这样的静态局部变量必须在第一次调用func时初始化一次。但是如何确保这一点呢?必须创建一个不可见的布尔变量,将其初始化为false,在初始化之前检查它,只有ini
func(double):                               # @func(double)
    push    rax
    mov al, byte ptr [rip + guard variable for func(double)::a]
    test    al, al
    jne .LBB0_3
    mov edi, guard variable for func(double)::a
    movsd   qword ptr [rsp], xmm0   # 8-byte Spill
    call    __cxa_guard_acquire
    movsd   xmm0, qword ptr [rsp]   # 8-byte Reload
    test    eax, eax
    je  .LBB0_3
    mov qword ptr [rip + func(double)::a], 0
    mov edi, guard variable for func(double)::a
    call    __cxa_guard_release
    movsd   xmm0, qword ptr [rsp]   # 8-byte Reload
.LBB0_3:
    addsd   xmm0, qword ptr [rip + func(double)::a]
    movsd   qword ptr [rip + func(double)::a], xmm0
    pop rax
    ret