2010-03-03 7 views
6

오랫동안 C++로 돌아가고 있으며 꽤 잘 알려진 정적 초기화 문제에 대한 이해가 조금 떨어졌습니다.C++ 정적 const 및 초기화 (큰 문제가 있습니까?)

의가 (이 단지 간결함을 위해 생략 된 I는 x와 y는 getter 및 setter와 개인해야한다고 알고 있습니다) 아래에 주어진 나는 간단한 클래스 Vector2 있다고 가정 해 봅시다 :

class Vector2 { 

public: 
    Vector2(float x, float y) :x(x), y(y) {}; 
    float x,y; 
} 

을 지금 , x 및 y를 1로 설정하여 Vector2를 나타 내기 위해 정적 const 멤버를 지정하려면 계속 진행하는 방법에 대해 확신이 없습니다. 정적 const 멤버가 정적 초기화 문제를 일으키지 않겠습니까? 쟤넨 괜찮아? 나는 다음과 같은 가능성을 놀겠다는 거 오전 :

가능성 1 :

// .h 
class Vector2 { 

public: 
    Vector2(float x, float y) :x(x), y(y) {} 
    static const Vector2 ONE; 
    float x,y; 
}; 

// .cpp 
const Vector2 Vector2::ONE = Vector2(1.f, 1.f); 

가능성 2 :

// .h 
class Vector2 { 

public: 
    Vector2(float x, float y) :x(x), y(y) {} 
    static const Vector2& getOne(); 
    float x,y; 
private: 
    static const Vector2 ONE; 
}; 

// .cpp 
const Vector2 Vector2::ONE = Vector2(1.f, 1.f); 

static const Vector2& Vector2::getOne() { 
    return ONE; 
} 

가능성 3 :

이제
// .h 
class Vector2 { 

public: 
    Vector2(float x, float y) :x(x), y(y) {} 
    static const Vector2& getOne(); 
    float x,y; 
}; 

// .cpp 
const Vector2& Vector2::getOne() { 
    static Vector2 one(1.f,1.f); 
    return one; 
} 

, 나의 선호하는 방법이 쓰기 가능성 2에서와 같이 될 것입니다. 왜냐하면 그것이 나를위한보다 편안한 구문이기 때문입니다. 그러나 다른 클래스의 다른 정적 메서드에서 getOne() 메서드를 호출하면 충돌 및 레코딩의 위험에 처하게됩니까? 내가 말했듯이 정적 정적 멤버가 아닌 정적 정적 멤버를 사용하고 있기 때문에이 질문을하고 있는데 정적 정적 멤버 문제는 많이 발견했지만 const 정적 문제는 없습니다.

저는 정적 인 const를 사용하고 있으며 가능성 3을 안전하게 유지해야한다는 사실 때문에 아무 것도 얻지 못할 것이라고 생각합니다. 그러나 누군가 나를 위해이 점을 밝혀 줄 수 있는지 물어보고 싶습니다.

나는 내가 묻는 바를 정확히 가리키는 링크를 여러 개 열어 놓고 있음을 깨닫는다. 그러나 나는 이것을보기 전에 보지 않고 찾지 못했다.

도움을 주신 모든 분들께 감사드립니다.

+0

다른 정적 초기화 프로그램 *에서 정적 멤버에 직접 액세스하려고 시도하면 큰 문제가 될 수도 있습니다. main()이 호출 된 후에 다른 함수에서 정적으로 액세스하는지 여부를 확인하는 것이 좋습니다. – sbk

+0

의견을 보내 주셔서 감사합니다. 내 질문에 좀 더 명확해야 했어. 내 의도는 정적 멤버가 별도의 cpp 파일에있는 다른 클래스의 정적 초기화 프로그램에서 사용되도록 안전하게 할 것인지 확인하는 것이 었습니다. 현재 다른 클래스 중 어느 것도 Vector2 :: getOne()을 사용하여 다른 정적 멤버를 초기화하지는 않지만 정적 이니셜 라이저 체인이있는 경우가 있습니다. 간단한 예제로 Vector2를 선택 했으므로 여기에서 전체 프로젝트에서 가장 좋은 패턴을 적용 할 수있는 의견을 이해할 수있었습니다. 많은 의견을 보내 주셔서 감사합니다. –

답변

10

3 가능성을 제외한 모든 항목은 정적 초기화 순서 실패로 고통을 겪습니다. 이는 수업이 POD가 아니기 때문입니다. C++ 0x에서이 문제는 생성자 constexpr을 표시하여 해결할 수 있지만 C++ 03에서는 그러한 해결책이 없습니다.

당신은 C++ 03의 문제를 해결하기 위해 생성자를 제거하고, 이것은 POD를 초기화

const Vector2 Vector2::ONE = { 1.f, 1.f }; 

사용하여 초기화하고 목록에있는 모든 초기화 정적의 목적을 위해 (상수 표현식입니다 수 있습니다 초기화). 초기화되기 전에 액세스 할 수있는 코드가 실행되기 전에 초기화됩니다.

3.6.2 정적 저장 기간 (3.7.1)와

개체는 다른 초기화가 수행되기 전에 (8.5) 제로 - 초기화되어야한다. 상수 표현식을 사용한 0 초기화 및 초기화를 총칭하여 정적 초기화라고합니다. 다른 모든 초기화는 동적 초기화입니다. 상수 표현식 (5.19)으로 초기화 된 정적 저장 기간을 가진 POD 유형 (3.9)의 객체는 동적 초기화가 수행되기 전에 초기화되어야합니다.

8.5.1/14 :

정적 저장 기간이 집합체는 중괄호 둘러싸인 초기화리스트로 초기화

모든 부재 이니셜 식은 정수 표현이며, 골재는 POD 타입이면 초기화는 정적 초기화 단계 (3.6.2) 동안 수행되어야한다; 그렇지 않으면 정적 표현식이나 초기화의 동적 단계에서 상수 표현식이있는 구성원의 초기화가 수행되는지 여부는 지정되지 않습니다.

+0

요하네스 주셔서 감사합니다. 대답 할 시간을 내 주셔서 감사 드리며 제 3의 가능성을 확인해 주셔서 감사합니다. 제 3의 것이 유일하게 안전한 것입니다. 나는 이것이 POD 초기화 경로를 내려가는 것을 생각하지 않았으므로 이것은 매우 유익하다. POD 접근법이 작동하지 않는 복잡한 클래스가 있지만 (모든 클래스가 POD로 취급 될 수있는 것은 아니기 때문에)이 클래스를 사용할 수있는 곳을 확실히 볼 수 있기 때문에 여전히 매우 편리합니다. 많은 감사합니다. –

+0

나는 당신의 대답을 결코 받아 들일 수 없다는 것을 깨달았습니다. 죄송하지만, 거의 1 년 후 지금은 수정되었습니다 –

1

가능성 3은 스레드로부터 안전하지 않습니다.

예를 들어 "C++ 범위 지정 정적 초기화가 의도적으로 스레드로부터 안전하지 않습니다!"를 참조하십시오. http://blogs.msdn.com/b/oldnewthing/archive/2004/03/08/85901.aspx

+1

이 답변은 더 이상 정확하지 않습니다 : 스레드 안전은 이제 [표준에 의해 부과됩니다] (http://stackoverflow.com/questions/8102125/is-local- 정적 변수 초기화 - thread-safe-in-c11) – Arnaud

관련 문제