首页 > 解决方案 > constexpr(即常量初始化)模板变量的初始化顺序是否有保证?

问题描述

en.cppreference.com/w/cpp/language/initialization

无序动态初始化,[原文如此]仅适用于未明确专门化的(静态/线程局部)类模板静态数据成员和变量模板(C++14 起)。

因此,静态模板似乎容易受到更糟糕的静态初始化顺序惨败 (TSIOF)版本的攻击(即在翻译单元中无序)。

使用 constexpr 会消除此漏洞吗?

即以下代码的输出是否保证success

显然,由于这个问题的性质,工作示例不足以作为答案;需要从标准中引用。(首选 C++17 答案)

#include<cassert>

template<class T> static constexpr T a = 41;
template<class T> static constexpr T b = a<T>+1;
int main(){
    assert(b<int> == 42);
    std::cout <<"success\n";
}

顺便说一句,如果有人是这方面的专家,我在这里有一个相关的、未回答的问题(这样的专家很容易回答)。此外,如果我的另一个问题的答案是否定的(即 constexpr 对翻译单元没有帮助),这将意味着什么?

更新:我需要澄清我关心的问题。最初的问题标题询问初始化顺序是否是 constexpr 模板变量的问题。我已经澄清了。我不关心示例中是否进行了动态初始化;不是。我担心的是,由于在动态初始化情况下不能假设有序初始化,那么可以在常量初始化情况下假设吗?在看到动态初始化的模板变量(在同一个翻译单元内)的行为之前,我从来没有想过这一点。然而,由于动态初始化、静态持续时间模板变量不提供有序初始化,我现在认为没有理由假设常量初始化、静态持续时间模板变量也保证有序初始化。

同样,如果动态初始化程序不是,我认为没有理由假设编译器内的常量初始化程序需要按顺序初始化。标准中没有警告说常量初始化是无序的是不够的。

我意识到有些人可能认为这是过度关注,但我正在开发安全关键软件,我的公司已暂停采用 C++14,直到这个问题得到解决。

标签: c++initializationglobal-variableslanguage-lawyerconstexpr

解决方案


基于basic.start.static

如果具有静态或线程存储持续时间的变量或临时对象由实体的常量初始化程序初始化,则执行常量初始化。

在您的代码中:

template<class T> static constexpr T a = 41; // constant initialization

正在进行不断的初始化,这使得:

template<class T> static constexpr T b = a<T>+1;

42由于模板的不断评估而被初始化。

其中指出(来自expr.const/8.7):

一个变量,其名称显示为一个潜在的常量评估表达式,该表达式要么是constexpr 变量,要么是非易失性 const 限定的整数类型或引用类型。

因此,可以保证输出始终是"success"满的。

注意来自basic.start.static/2

零初始化常量初始化一起称为 静态初始化

--不是动态初始化


推荐阅读