当前位置: 首页 > 知识库问答 >
问题:

MSVC 2017 在单个翻译单元中违反静态初始化顺序

谢承
2023-03-14

MSVC 2017社区-std=c 17在以下示例中阻塞:

#include <iostream>

struct TC
{
    static TC const values[];
    static TC const& A;
    static TC const& B;
    static TC const& C;

    int const _value;
};

inline constexpr TC const TC::values[]{ { 42 }, { 43 }, { 44 } };
inline constexpr TC const& TC::A{ values[0U] };
inline constexpr TC const& TC::B{ values[1U] };
inline constexpr TC const& TC::C{ values[2U] };

int main(int, char**) noexcept
{
    std::cout << std::boolalpha
        << "&A == &values[0]? " << (&TC::A == &TC::values[0U]) << "\n" 
        << "&B == &values[1]? " << (&TC::B == &TC::values[1U]) << "\n"
        << "&C == &values[2]? " << (&TC::C == &TC::values[2U]) << "\n";
    return 0;
}

预期的输出是:

&A == &values[0]? true
&B == &values[1]? true
&C == &values[2]? true

这是gcc和clang产生的,但MSVC给出:

&A == &values[0]? true
&B == &values[1]? false
&C == &values[2]? false

如果移除了< code>_value成员,并且没有用户定义的构造函数,MSVC会给出正确的结果。

由于所有这些都在单个翻译单元内,我的理解是这属于部分有序动态初始化:

2)部分有序的动态初始化,适用于所有不是隐式或显式实例化的特化的内联变量。如果在每个翻译单元中,在有序或部分有序的W之前定义了部分有序的V,则V的初始化在W的初始化之前排序(或者发生-之前,如果程序启动一个线程)

我不能使用函数来确保初始化顺序,因为我需要值和引用它们。

所以问题是,MSVC 违反了这里的标准*,对吗?

*当然cppreference.com不是“标准”,但我假设那里的信息来源正确。

共有1个答案

容阳焱
2023-03-14

我将同样的问题归结为这个更简单的例子:

#include <iostream>

int values[3];
constexpr int& v{ values[1] };

int main()
{
    std::cout << &v << ", " << &values[1] << "\n";
    return 0;
}

使用最新的MSVC 2017社区,输出:

0119D035, 0119D038

如果删除 constexpr,则不会发生此问题。

所以我认为这是一个带有 constexpr 引用初始化的编译器错误。引用已初始化为

铌。如果有人不熟悉 constexpr 引用定义,请参阅此处或此处。constexpr 强制初始值设定项是具有静态存储持续时间的对象。

 类似资料:
  • 问题内容: 我正在尝试发现初始化发生的顺序,或者更确切地说,为什么要按此顺序进行初始化的原因。给定代码: 输出: 但是,将的声明移动到初始化块之前会产生: 而且我完全不知道为什么会以这种顺序发生。此外,如果我在的声明中消除了关键字,则init块和构造函数均不会触发。谁能帮我这个忙吗? 问题答案: 我认为您只是缺少JLS的12.4.2节,其中包括: 接下来,以文本顺序执行类的类变量初始化器和静态初始

  • 问题内容: 当我运行此代码时,答案是1,我想应该是2。初始化的顺序和每一步中k的值是什么? 编辑1:作为后续的“ k设置为默认值”,那么为什么下一个代码不能编译?出现错误“在定义字段之前无法引用它”。 编辑2:出于某种我不知道的原因,它^可以在其“ Test.k”代替“ k”时使用。 感谢所有的答案。这将满足:D 问题答案: 它们按照您编写它们的顺序执行。如果代码是: 然后输出变为2。 初始化的顺

  • 问题内容: 这是一段Java代码: 它如何编译?初始化后已执行变量“ ture”的声明。据我所知,静态块和字段已经按照它们出现的顺序执行了。 现在,为什么实例块中的值9已被打印3次?顺便说一句,该类的实例已创建了3次。那不是功课,我正在学习Java进行认证。 问题答案: 关于第一个问题,静态块确实按照它们出现的顺序进行处理,但是在处理静态块之前,先处理声明。声明作为类 准备工作 的一部分(JLS§

  • 问题内容: 我尝试了解通过引用同一封闭类对象初始化静态字段时初始化顺序的行为。 上面这段代码的输出是: 如果我将变量修改为除plain之外的其他任何内容: 输出为: 为什么会这样呢? 请注意,即使同时声明了两者,输出也是如此,在这种情况下,声明之前 问题答案: 静态最终成员先于其他静态成员初始化。 非最终静态成员按出现顺序初始化 因此,在您的第一种情况下: 构造函数在初始化之前首先被调用,因此被显

  • 问题内容: 如何在Java中初始化? 我知道这是一个接口,可以使用或实现,但是在初始化时会出现错误的不兼容类型: 那我该如何进行呢? 问题答案: 用 或从Java 1.7开始

  • 问题内容: 我想知道为什么默认情况下C,C ++和Java中的确切静态变量初始化为零?为什么对局部变量不是这样? 问题答案: 为什么要对静态变量进行确定性初始化而对局部变量不进行初始化? 了解如何实现静态变量。 它们的内存在链接时分配,并且它们的初始值也在链接时提供。 没有运行时开销。 另一方面,用于局部变量的内存是在运行时分配的。堆栈必须增长。你不知道以前在那里。如果需要,可以清除该内存(将其清