Подтвердить что ты не робот

Как инициализируется std:: cout?

Что я знаю о С++, так это то, что порядок конструкций (и разрушений) глобальных экземпляров не должен приниматься.

Пока я пишу код с глобальным экземпляром, который использует std::cout в конструкторе и деструкторе, у меня возник вопрос.

std::cout также является глобальным экземпляром iostream. Является ли std::cout гарантией инициализации перед любыми другими глобальными экземплярами?

Я написал простой тестовый код, и он отлично работает, но все же я не знаю почему.

#include <iostream>

struct test
{
    test() { std::cout << "test::ctor" << std::endl; }
    ~test() { std::cout << "test::dtor" << std::endl; }
};

test t;

int main()
{
    std::cout << "Hello world" << std::endl;
    return 0;
}

Он печатает

test::ctor
Hello world
test::dtor

Есть ли вероятность, что код не будет работать, как ожидалось?

4b9b3361

Ответ 1

Ответ отличается в зависимости от того, используете ли вы С++ 03 или С++ 11.

В С++ 11 ваш код гарантированно работает, но в С++ 03 он не указан; ваша единственная гарантия заключается в том, что к моменту ввода main() стандартные потоки были инициализированы. (Тем не менее, все основные реализации инициализируют их до запуска любой динамической инициализации, что делает их прекрасными для использования.)

Вы можете принудительно инициализировать, создав объект std::ios_base::Init, например:

#include <iostream>

struct test
{
    test() { std::cout << "test::ctor" << std::endl; }
    ~test() { std::cout << "test::dtor" << std::endl; }

private:
    std::ios_base::Init mInitializer;
};

test t;

int main()
{
    std::cout << "Hello world" << std::endl;
    return 0;
}

Теперь, когда test создает, он инициализирует mInitializer и гарантирует, что потоки готовы к использованию.

С++ 11 исправил это слегка раздражающее поведение, действуя так, как будто каждый экземпляр #include <iostream>, за которым следует static std::ios_base::Init __unspecified_name__;. Это автоматически гарантирует, что потоки готовы к использованию.

Ответ 2

Согласно §27.3/2:

Построены объекты [std:: cin, std:: cout и т.д.], а ассоциации устанавливаются в какое-то время до или во время первого время создается объект класса ios_base:: Init, и в любом случае перед тем как тело основного начнет выполнение.

Ответ 3

Ваш вопрос о порядке построения статических объектов. Я считаю, что спецификация языка оставляет его undefined.

GCC имеет атрибут init_priority для воспроизведения с порядком.

И я считаю, что вы не должны так беспокоиться на практике.