类模板中静态数据的初始化顺序

时间:2012-04-04 12:24:28

标签: c++ templates static initialization static-initialization

// File: InitFirst.h

#pragma once

template <int val>
struct InitFirst
{
    static float s_dividedByThree;
};

template <int val>
float InitFirst<val>::s_dividedByThree = val / 3.0;

// File: Test.h

#include <conio.h>
#include <tchar.h>

#include "InitFirst.h"

float g_shouldBeOneThird = InitFirst<1>::s_dividedByThree;

int _tmain(int argc, _TCHAR* argv[])
{
    _cprintf("%f\n", g_shouldBeOneThird);
    getch();
    return 0;
}

g_shouldBeOneThird是否保证初始化为0.333左右?换句话说,静态初始化的InitFirst&lt; 1&gt; :: s_dividedByThree是否保证在用于静态初始化g_shouldBeOneThird时被初始化?

1 个答案:

答案 0 :(得分:2)

从标准(3.6.2):

  

具有静态存储持续时间(3.7.1)的对象应进行零初始化   (8.5)在进行任何其他初始化之前。参考用   静态存储持续时间和具有静态存储的POD类型的对象   持续时间可以用常量表达式初始化(​​5.19);这是   称为常量初始化。零初始化和   常量初始化称为静态初始化;所有其他   初始化是动态初始化。静态初始化应该   在任何动态初始化发生之前执行。动态   对象的初始化是有序的还是无序的。   显式专用类模板静态数据的定义   成员已订购初始化。其他类模板静态数据   成员(即隐式或显式实例化的专业化)   有无序的初始化。命名空间中定义的其他对象   范围已订购初始化。单个内定义的对象   翻译单元和有序初始化应初始化   按翻译单位中的定义顺序排列。命令   对于具有无序的对象,未指定初始化   初始化和在不同翻译单元中定义的对象。

在这种情况下,由于您使用常量表达式初始化float InitFirst<val>::s_dividedByThree,这将在任何动态初始化(f.x float g_shouldBeOneThird)之前发生。虽然我有一种感觉,这个简化的例子可能是对动态初始化的情况的简化,但相关部分是:“在单个翻译单元中定义的对象和有序初始化应按其定义的顺序初始化。翻译单位。“。

有一个技巧可以确保在使用它们时初始化全局变量(类型)。诀窍是将它们作为全局函数中的静态局部变量。由于本地静态变量在第一次被访问时被初始化,因此初始化顺序不再是问题:

template <int val>
struct InitFirst
{
    static float & s_dividedByThree();
};

template <int val>
float & InitFirst<val>::s_dividedByThree(){
    static float staticVariable = val / 3.0;
    return staticVariable;
}

然后,您可以像以前一样访问几乎这些变量:

float g_shouldBeOneThird = InitFirst<1>::s_dividedByThree();

请注意,本地静态变量的初始化在多个线程下是不安全的(它们在标准中不应该是安全的)。如果这是您的问题,您可能希望保护初始化 一些锁。编译器当然可以生成安全代码,这是gcc默认执行的操作(也可能是其他代码)。