类模板中的静态数据的初始化命令(Initialization order of static dat

2019-06-23 09:16发布

// 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 <1> :: s_dividedByThree保证通过它的用于静态初始化g_shouldBeOneThird的时候被初始化?

Answer 1:

从标准(3.6.2):

具有静态存储的持续时间(3.7.1)的对象应是零初始化(8.5)的任何其它初始化发生之前。 具有静态存储持续时间和POD类型具有静态存储持续时间的对象的引用可与常量表达式(5.19)被初始化; 这就是所谓的常量初始化。 总之,零初始化和常数初始化被称为静态初始化; 所有其他初始化是动态初始化。 任何动态初始化发生之前,应进行静态初始化。 对象的动态初始化或者有序或无序。 明确专业类模板静态数据成员的定义已下令初始化。 其他类模板静态数据成员(即,隐式或显式实例特)有无序的初始化。 在命名空间范围定义的其他对象已下令初始化。 一个翻译单元内,并用命令初始化定义的对象应在其定义的翻译单元的顺序进行初始化。 初始化的顺序是不确定与无序初始化对象,并在不同的翻译单元定义的对象。

在你的情况在这里,因为你初始化float InitFirst<val>::s_dividedByThree用常量表达式,这将在任何动态初始化(FX之前发生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在默认情况下(可能其他人也)。



文章来源: Initialization order of static data inside class template