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

3
// 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时已被初始化?

1个回答

3

根据标准(3.6.2):

具有静态存储期(3.7.1)的对象在进行任何其他初始化之前都必须进行零初始化(8.5)。具有静态存储期和POD类型的对象引用可以使用常量表达式(5.19)进行初始化;这称为常量初始化。零初始化和常量初始化一起被称为静态初始化;所有其他初始化都是动态初始化。必须在进行任何动态初始化之前执行静态初始化。对象的动态初始化是有序的或无序的。显式专门化类模板静态数据成员的定义具有有序初始化。其他类模板静态数据成员(即隐式或显式实例化的专门化)具有无序初始化。命名空间范围内定义的其他对象具有有序初始化。在单个翻译单位中定义并进行有序初始化的对象应按其在翻译单位中的定义顺序进行初始化。对于具有无序初始化的对象和在不同翻译单位中定义的对象,初始化顺序是未指定的。

在您的情况下,由于您正在使用常量表达式初始化 float InitFirst<val>::s_dividedByThree,因此这将在任何动态初始化之前发生(例如 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默认情况下所做的(可能其他编译器也是如此)。


我没有点踩,但我认为最后一部分是错误的(从“然而”开始),这就是阻止我点赞的原因... - David Rodríguez - dribeas
@DavidRodríguez-dribeas,您说得完全正确,我一直以为是另外一种情况。这也解释了为什么模板类的静态成员具有无序初始化。链接器可以选择将它们放在任何地方,同时折叠模板实例。 - enobayram
@enobayram 你猜对了,我的实际代码并没有使用const表达式来初始化数据,因此初始化将是动态的。如果我理解正确,初始化顺序和因此程序行为会是未指定的。 - zeroes00
该技巧也可以在https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use(以及其他一些技巧)中找到。但是每次访问都会有微小的运行时成本。 - user202729

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接