编辑:我知道在循环体之前声明对象更有效,因为它每次函数调用调用构造函数和析构函数,而不是每次循环迭代调用一次。比方说,由于这种推理,类型A的对象在循环体之外更有效。
我想知道下面的
void foo()
{
static A var; //A is a class with a constructor
... //stuff done with var
}
比更有效率
void foo()
{
A var; //A is a class with a constructor
... //stuff done with var
}
因为前者会调用A的构造函数和析构函数一次,而不是后者每次调用foo都会调用。我一般会在所有本地对象中提出这个问题。
首先,它在语义上是不同的。你在比较两种不同的东西。如果你不在乎语义上的差异,任何一个都可能比另一个更快。如果A
的构造没有多大作用,例如,仅仅初始化int
,那么第二版本很可能更快,例如,因为编译器需要知道它是否在运行时初始化了var
,而在C++11中,初始化是线程安全的。如果在某种程度上涉及A
的构建,则第一个版本可能更快。
对于任何给定的应用程序,唯一的方法都是测量。
经验法则:编写您的意思(本地对象还是逻辑上每次调用都需要共享它?)并让编译器担心优化。
我为非平凡类型的常量破例。例如,"static const std::string"比"const std::string"更好,因为它每次都保存动态分配。但是,如果对象不包含动态分配,并且大小不是几十个字节,则将其作为局部变量。
出于效率的原因,没有必要使基本类型(如const int
或const char *const
)成为静态的,尽管这不会有什么坏处。
由于静态对象在线程之间共享,编译器可能需要在每次需要使用它时检查它是否已被另一个线程更新,而局部变量则不可能是这种情况。因此,不要认为静态将是"最快的"。(如何工作取决于您的编译器实现)
当然,您还需要意识到,使其静态或不静态可能会改变程序的行为。我上面的信息假设选择不会。
首先要做对,然后要做快。带有静态变量的版本会继承上一次调用的值;除非您需要在多个调用中保留信息,否则良好的设计会调用将变量设置为已知状态,这就是构造函数所做的。如果你不使用构造函数,也就是说,你让变量成为静态的,那么你必须做一些其他的事情来让变量进入一个已知的状态;也就是说,您最终调用了一个函数,该函数完成了构造函数应该完成的操作,但语法更加模糊。
这里有一个过于简单化的例子:
void f(int j) {
static int i = 0;
i = 0; // reset, because previous call left i with some spurious value
while (i < j)
std::cout << i << 'n';
}
除此之外,在调用之间共享该变量意味着在多线程程序中,您必须同步对该函数的所有调用,这会带来一个瓶颈,几乎肯定会抵消每次使用对象时不构建对象带来的任何性能增益。