2012-01-09 4 views
33

내가 C++에 대해 알고있는 것은 전역 인스턴스의 구성 (및 파기) 순서를 가정해서는 안된다는 것입니다.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 

코드가 예상대로 실행되지 않는 가능성이있다 인쇄? §27.3/2 따르면

+1

관련 항목 http://stackoverflow.com/questions/6919593/is-cout-guaranteed-available-during-static-deinitialization 또한 답변의 구성에 대해 다룹니다. – adl

+0

전역 범위에서 정적 저장 기간 개체의 초기화 순서를 가정 할 수는 없지만 초기화 순서를 강제하는 트릭이 있습니다. –

+0

추 신 :또한 파괴 순서가 보장된다는 점에 유의하십시오 (구조의 역함수). –

답변

36

답변은 C++ 03 또는 C++ 11을 사용하는지 여부에 따라 다릅니다.

C++ 11에서는 코드가 작동하지만 C++ 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; 
} 

이제 때 testmInitializer을 초기화하고 스트림을 사용할 준비가되었음을 보장합니다.

C++ 11은 #include <iostream>의 모든 인스턴스 다음에 static std::ios_base::Init __unspecified_name__;이 오는 것처럼 행동하여 약간 불쾌한 동작을 수정했습니다. 이렇게하면 자동으로 스트림을 사용할 준비가되었습니다.

+2

C++ 03에서 명확한 의도는 발자국에 표시된대로 std :: cin/std :: cout 개체가 다른 개체보다 먼저 완전하게 구성되도록하는 것입니다. –

10

:

오브젝트 [표준 : CIN, 표준 : COUT 등]가 생성되고, 연결 전에 또는 몇 시간에 수립 처음에는 시간 동안 ios_base :: Init 클래스의 객체가 생성되고, 어떤 경우에는 이 실행되기 전에 main이 실행을 시작합니다.

+1

다른 정적 객체와 비교하여'std :: cout'의 생성 순서에 대해서는 아무 것도 말하지 않습니다. –

+10

@BasileStarynkevitch : 사실 일종의 각주 265 (§27.3/2에서 참조)는 "정적 객체의 생성자와 소멸자는 이러한 객체에 액세스하여 stdin에서 입력을 읽거나 stdout 또는 stderr에 출력을 쓸 수 있습니다." 그것은 규범 적이 아닐 수도 있지만 적어도 그의 코드가 작동해야한다는 * 의도 *를 명확하게 기술하고 있습니다. –

+3

@BasileStarynkevitch : 실제로 그렇습니다. 문단은 다음과 같이 계속됩니다. "번역 단위에 을 포함시킨 결과는 이 정적 저장 기간이있는 ios_base :: Init의 인스턴스를 정의한 것과 같아야합니다." 그리고 같은 번역 단위의 static non-local 변수는 선언 된 순서대로 초기화되기 때문에,'cout'은 다른 non-local statics보다 먼저 초기화 된 것이 보장됩니다. (여러분이 변수를 선언하기 전에'#include '이라고 가정합니다.) – knatten

2

귀하의 질문은 정적 개체의 건설 순서에 관한 것입니다. 나는 언어 사양이 정의되지 않은 것으로 믿는다.

GCC에는 주문과 함께 재생할 init_priority 속성이 있습니다.

그리고 실제로 그렇게 많이 걱정하지 않아야한다고 생각합니다.

관련 문제