2013-08-27 2 views
4

일부 초기화 작업을 수행하려면 다음 코드 섹션과 같은 것을 사용하고 있습니다. 나는 p<T>::i_의 초기화가 정렬되어 있지 않다는 것을 알고 있습니다. 나는 h이 주문되었다는 것을 염두에두고, 초기화 된 순서에 대해 추론 할 수 있어야한다. h의 정의 앞에 p의 헤더가 포함되어 있다고 가정하면 h보다 먼저 p<T>::i_이 초기화된다는 보장이 있습니까?초기화 순서 보장

struct helper 
{ 
    template <typename T> 
    helper(const T&, int i) 
    { 
     p<T>::i_::push_back(i); 
    } 
}; 
static helper h; 

클래스 p는하기와 같이 정의된다.

template <typename T> 
struct p 
{ 
    static std::vector<int> i_; 
}; 
template <typename T> 
std::vector<int> p<T>::i_; 
+0

이것은 컴파일되지 않습니다. - 'helper'는 기본 생성자를 가지고 있지 않습니다. –

+0

'h '를 초기화하는 데 사용되는 생성자는 무엇입니까? –

+3

"나는'h'가 주문되었다고 믿습니다. 무엇에 비해 주문 했습니까? – jrok

답변

6

정적 저장 기간을 가진 객체의 초기화 순서는 번역 단위에서 정의되지 않고 각 번역 단위 내에서 순차적입니다.

정적 저장소가있는 개체 중 하나가 템플릿 클래스의 정적 멤버이기 때문에 특별한 경우가 더 복잡합니다. 실질적인 방법으로 멤버 p<T>::i_에 액세스하는 각 번역 단위가 심볼을 만들고 적절한 초기화 코드를 추가한다는 것입니다. 나중에 링커는 인스턴스 중 하나를 선택하여 보관합니다. 번역 단위에 p<T>::i_으로 정의되어 있고h으로 정의되어있는 경우 링커가 보관할 p<T>::i_의 인스턴스가 무엇인지 알지 못하며 이는 다른 번역 단위에있는 것이므로 순서가 보장되지 않을 수 있습니다 .

일반적으로 전역 개체를 사용하는 것은 좋지 않은 생각입니다. 전역이없는 프로그램을 다시 디자인 해 보시기 바랍니다.

+0

+1 번역 단위/링커 관련을 언급합니다. template이 인스턴스화 될 때'static' non-template 변수가 초기화되는지 궁금합니다. 또는 템플릿이 인스턴스화되는지 여부에 관계없이 초기화됩니까 (이상하게 보입니다)? – lapk

+0

중요한 점은 템플릿의 암시 적 인스턴스화는 정적 멤버의 초기화를 트리거하지 않는다는 것입니다. 그것들은 정의가 필요한 방식으로 사용될 때 초기화됩니다. – jrok

+0

@PetrBudnik : 템플릿을 명시 적으로 인스턴스화하지 않는 한 모든 구성원이 필요에 따라 인스턴스화됩니다. 프로그램에서 템플릿의 정적 멤버를 사용하지 않으면 멤버가 사용되지 않는 한 컴파일러에서 인스턴스화되지 않습니다. –

5

전역 또는 이름 공간 범위의 개체는 하나의 번역 단위 내에서 위에서 아래로 구성됩니다. 다른 번역 단위 사이의 전역 또는 네임 스페이스 수준의 구성 순서는 정의되지 않습니다. 가장 합리적인 방법은, 적절한 접근 자 함수 내에서 예를 들어 객체를 래핑하는 번역 단위 사이의 초기화를 주문하기 :이 C++ 03 (C 등의-스레드로부터 안전하지 않습니다, 그러나,

template <typename T> 
something<T>& get() { 
    static something<T> values; 
    return value; 
} 

참고 ++ 03에는 어쨌든 스레드 개념이 없습니다). C++ 11에서는 스레드로부터 안전합니다.

0

아니요, 보장 할 수는 없습니다. 당신이 할 수있는 일

그러나입니다 :

template<typename T> 
std::vector<int>& registry() { 
    static std::vector<int> reg; 
    return reg; 
} 

... 
registry<T>().push_back(i); 
... 

더 나은

가 시작하는 동안 너무 똑똑 일을 방지하는 것입니다.

main 시작 전이나 끝나기 전에 디버깅하는 것은 정말 악몽입니다 (IMO는 표준에서 100 %까지 다루지 못함). 간단한 등록은 괜찮지 만 실패 할 수있는 일은 절대하지 마십시오.

나는이 접근 방식을 명시 적 초기화/종료로 옮겼으며 결코 뒤돌아 보지 않았습니다.

+0

동적 초기화 디버깅은 생각만큼 힘들지 않을 수도 있습니다. 플랫폼 독립적 심볼을 사용하면 동적 초기화 항목을 표시하고 다른 기능과 마찬가지로 실행할 수 있습니다. –

+0

@ user1131467 : 디버깅 도구가 초기화 및 종료 중에 예상대로 작동하지 않는 것을 보았습니다. 초기화하는 동안 표준 라이브러리가 얼마나 초기화되고 사용할 수 있는지, 정적 기간 인스턴스가 파괴되는 동안 이미 표준 라이브러리가 얼마만큼 종료되었는지는 명확하지 않습니다. 예를 들어 특정 경우에 응용 프로그램을 종료 할 때 자동으로 segfaults를 삼키는 창을 추가하십시오. – 6502