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

问题描述 投票:0回答:1

我有以下程序:

#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的ctor,我们将看到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)

c++ visual-c++ constexpr static-variables static-initialization
1个回答
5
投票

但是bar的构造函数似乎是一个常量表达式,所以我们将对bar进行静态初始化。

这是一个错误的理解。

constexpr构造函数也可用于构造非const对象。发生这种情况时,将使用动态初始化初始化该对象。在你的情况下,bar是一个非const对象。因此,使用动态初始化初始化它是有意义的。

将代码更改为:

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

constexpr Bar bar;

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

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

bar.value = 1; 

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

© www.soinside.com 2019 - 2024. All rights reserved.