Конструктор Constexpr для статической переменной приводит к динамической инициализации - PullRequest
0 голосов
/ 04 апреля 2019

У меня есть следующая программа:

#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 ctor должен быть вызван перед foo, и мы увидим 1 как вывод. И я наблюдаю такой результат для GCC 8.3.0 и Clang 8.0.0. Но для Visual C ++ фактический вывод равен 0, и когда я отлаживаю приложение, я вижу, что сначала выполняется динамическая инициализация foo, а затем выполняется динамическая инициализация bar.

Является ли поведение, которое я наблюдаю (bar.value == 0), допустимым в соответствии со стандартом C ++ 17?

Я использую компилятор C ++ версии 19.16.27027.1 для x86. Отладочная сборка или сборка выпуска с ctor, помеченными __declspec(noinline).

1 Ответ

5 голосов
/ 04 апреля 2019

Но конструктор 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, чтобы он мог быть инициализирован во время статической инициализации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...