将函数内的大变量声明为“static”在性能上有什么不同吗?

Is there any difference in performance to declare a large variable inside a function as `static`?

不确定之前是否有人问过这个问题。在回答 时,我问自己以下问题。考虑一下:

void foo()
{
    int i{};
    const ReallyAnyType[] data = { item1, item2, item3,
        /* many items that may be potentially heavy to recreate, e.g. of class type */ };
    /* function code here... */
}

现在理论上,每次控制达到功能时都会重新创建局部变量,对吗? IE。看看上面的 int i - 它肯定会在堆栈上重新创建。上面的数组呢?编译器能否聪明到优化它的创建只发生一次,还是我在这里需要一个 static 修饰符?如果数组不是 const 怎么办? (好吧,如果不是 const,我可能只创建它一次就没有意义,因为由于在函数执行期间进行修改,调用之间可能需要重新初始化到默认状态。)

听起来像是一个基本问题,但出于某种原因我仍在思考。另外,忽略 "why would you want to do this" - 这只是一个语言问题,不适用于特定的编程问题或设计。我在这里指的是 C 和 C++。如果两者在这个问题上有不同之处,请概述。

编译器几乎肯定会做任何被认为是最佳的事情,但很可能会将它放在只读内存中,并将您的局部变量转换为指向只读内存中数组的指针。这假设您的数组等效于 POD 类型(或由 POD 类型组成的 class;如果您的 class 做了一些不平凡的事情 and/or 修改了其他东西,编译器就没有办法可以公平地进行此优化)。

这里有两个问题,我觉得:

  • 编译器可以 优化非static const 对象有效地static 以便它是只创建一次;和

  • 给定的编译器会这样做是否合理。

我认为第二个问题的答案是"No",因为我看不出做大量的控制流分析来节省程序员输入单词的麻烦的意义static.然而,我经常对人们花时间编写的优化感到惊讶(而不是 I 认为他们应该致力于的优化:-))。尽管如此,如果您需要的话,我强烈建议您使用 static 这个词。

对于第一个问题,在某些情况下编译器可以根据"as-if"规则进行优化,但在极少数情况下可以解决。

首先,如果初始化器中的任何对象或子对象具有非平凡的constructor/destructor,那么construction/destruction是可见的,这不是复制省略的例子。 (当然,本段仅适用于 C++。)

如果初始化列表中的任何计算有明显的副作用,情况也是如此。

不言而喻,如果任何子对象的值不是常量,则需要在每次构造时对该子对象进行计算。

如果对象和所有子对象都是普通可复制的,所有初始化列表计算都是常量,唯一的构造成本是从模板复制到对象,那么编译器仍然无法执行优化对象的多个活动实例的地址是否有可能同时可见。例如,如果函数是递归的,并且在某处使用了对象的地址(对于数组来说很难避免),那么可能会比较来自函数的不同递归调用的其中两个对象的地址。而且它们必须比较不相等,因为它们实际上是不同的对象。 (而且,现在我想起来了,这个函数在多线程环境下甚至不需要递归。)

因此,对于希望将该对象优化为单个静态实例的编译器来说,举证责任非常高。正如我所说,给定的编译器很可能实际上尝试执行该任务,但我绝对不希望它这样做。