c++ - 静态变量的 Constexpr 构造函数导致动态初始化

标签 c++ visual-c++ constexpr static-variables static-initialization

我有以下程序:

#include <iostream>

void Init();

struct Foo {
    Foo() {
        int *p = new int; // just to make sure Foo's ctor is not a constant expression
        Init();
    }
} foo;

struct Bar {
    constexpr Bar()
        : value(0) { }
    int value;
} bar;

void Init() {
    bar.value = 1;
}

int main()
{
    std::cout << bar.value << std::endl;
}

这里 foo 的构造函数不是常量表达式,所以我们将对 foo 进行动态初始化。但是 bar 的构造函数似乎是一个常量表达式,所以我们将对 bar 进行静态初始化。因此,bar 的构造函数必须在 foo 的构造函数之前被调用,我们将看到 1 作为输出。我观察到 GCC 8.3.0 和 Clang 8.0.0 的结果。但是对于 Visual C++,实际输出是 0,当我调试应用程序时,我看到 foo 的动态初始化是先进行的,然后是 bar的动态初始化完成。

根据 C++ 17 标准,我观察到的行为 (bar.value == 0) 是否有效?

我将 C++ 编译器版本 19.16.27027.1 用于 x86 调试构建或发布构建,其中 ctor 的标记为 __declspec(noinline)

最佳答案

But bar's constructor seems to be a constant expression, so we'll have static initialization of bar.

这是错误的理解。

constexpr 构造函数也可用于构造非const 对象。当发生这种情况时,该对象将使用动态初始化进行初始化。在您的情况下, bar 是一个非 const 对象。因此,使用动态初始化对其进行初始化是有道理的。

将您的代码更改为:

struct Bar {
    constexpr Bar()
        : value(0) { }
    int value;
};

constexpr Bar bar;

应将 bar 的初始化更改为静态初始化。

但是,如果将bar 更改为const 对象,您将无法使用

bar.value = 1; 

Init() 中。我只是想指出如何更改 bar 以便它可以在静态初始化期间进行初始化。

关于c++ - 静态变量的 Constexpr 构造函数导致动态初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55522698/

相关文章:

c++ - 难以理解 C++14 宽松的 constexpr 限制

c++ - 在类范围内将指针传递给 constexpr 函数时是否滥用推断父模板的参数

c++ - std::shared_ptr 在按引用传递时如何跨类层次结构转换?

c++:在原始指针映射中复制、删除和运算符=

c++ - 为什么通过地址传递大括号初始化的临时变量需要显式转换为 MSVS 中的相同类型

visual-c++ - Cl.exe 返回错误代码 D8050

c++ - 制作按钮并处理它们

用于使用 MySql 的 C++ 库

c++ - 可以在下面定义一个更简单的函数-(to.string())

c++ - 在引用定义中使用 constexpr 和 const