2

在 C++ 中,在合理的编译器中,使用变量值而不是常量值初始化静态变量的预期运行时成本是多少?

例如考虑以下代码:

bool foo();
bool baz1() {
  const bool value = foo();
  static bool alternate1 = value;
  static bool alternate2 = false;

  // Do something.
  return alternate1;
}

alternate1和之间的预期运行时成本差异是alternate2多少?

4

4 回答 4

5

从编译时常量(备选方案 2)初始化很可能发生在程序启动期间,每次调用函数时都没有成本。

局部静态变量的线程安全初始化将导致编译器生成类似下面的伪代码:

static bool alternate1;

static bool __initialised = false;
static __lock_type __lock;
if (!__initialised) {
    acquire(__lock);
    if (!__initialised) {
        alternate1 = value;
        __initialised = true;
    }
    release(__lock);
}

因此,每次调用函数时都可能需要对标志进行测试(可能涉及内存屏障或其他同步原语),以及第一次获取和释放锁的进一步成本。

请注意,在您的代码中,foo()每次都会调用,无论变量是否已初始化。如果您将初始化更改为

static bool alternate1 = foo();

当然,细节取决于实现;这是基于我对 GCC 生成的代码的观察。

于 2012-07-10T13:56:34.097 回答
1

static变量在程序开始时被初始化,这意味着初始化只会发生一次。仅一个布尔值的成本非常低,对您alternate1而言,执行的成本foo()是多少,在您的示例中并不多,因为它只是一个空函数。

概括地说,成本将是初始化您的基本类型(int、float 等)或初始化任何用户定义类型/库定义类型的成本(运行 ctor)的最大成本。任何static用函数初始化的,然后最大值将是正在执行的函数的成本。

于 2012-07-10T13:48:58.047 回答
1

您的问题似乎不是关于一般的静态变量,而是关于在函数内声明的静态变量。

从运行时值初始化此类变量的额外运行时成本源于多个来源

  1. 当控件第一次传递其声明时(如果有的话),此类变量应仅初始化一次。为了实现为每个这样的变量分配一个额外的布尔变量/标志,并在每次控制通过声明时检查。如果标志表明该变量尚未初始化,则它会被初始化。

  2. 对于那些具有非平凡析构函数的静态变量,语言必须保证它们在程序终止时的销毁顺序与其构造顺序相反。由于构建顺序是在运行时确定的,因此程序必须准备一个运行时结构来安排未来的销毁。对于具有非平凡析构函数的变量,这也是步骤 1 的一部分:它们按照构造顺序注册在构造对象的“列表”中。“列表”通常被实现为一个预分配的数组(因为它的最大大小在编译时是已知的)。

  3. 在多线程配置中,上述步骤可能/将伴随着额外的锁定/解锁步骤。

Since these are all "household" expenses implemented "under the hood", the actual cost might greatly depend on the implementation. See/profile the code your specific compiler generates.

于 2012-07-10T14:20:10.113 回答
-1

设置alternate1值意味着调用函数,即使函数返回静态值,您也必须保存堆栈,调用函数,获取其返回值,恢复堆栈并将值分配给变量。

从字面上看,在第一种情况下,您将执行至少 8 行汇编代码,而在第二种情况下,您将只执行一行。

于 2012-07-10T13:56:50.760 回答