development

C ++ 정적 초기화 순서

big-blog 2020. 12. 5. 10:07
반응형

C ++ 정적 초기화 순서


C ++에서 정적 변수를 사용할 때 종종 하나의 변수를 초기화하여 다른 변수를 생성자로 전달하려고합니다. 즉, 서로 의존하는 정적 인스턴스를 만들고 싶습니다.

단일 .cpp 또는 .h 파일 내에서 이것은 문제가되지 않습니다. 인스턴스는 선언 된 순서대로 생성됩니다. 그러나 다른 컴파일 단위의 인스턴스로 정적 인스턴스를 초기화하려는 경우 순서를 지정할 수 없습니다. 그 결과 날씨에 따라 다른 인스턴스에 의존하는 인스턴스가 생성되고 나중에 다른 인스턴스가 생성 될 수 있습니다. 그 결과 첫 번째 인스턴스가 잘못 초기화됩니다.

정적 개체가 올바른 순서로 생성되는지 확인하는 방법을 아는 사람이 있습니까? 나는 오랜 시간 동안 해결책을 찾아서 (Schwarz Counter 솔루션을 포함하여) 모두 시도했지만 실제로 작동하는 것이 있는지 의심하기 시작합니다.

한 가지 가능성은 정적 함수 멤버의 트릭입니다.

Type& globalObject()
{
    static Type theOneAndOnlyInstance;
    return theOneAndOnlyInstance;
}

실제로 이것은 작동합니다. 유감스럽게도 globalObject.MemberFunction () 대신 globalObject (). MemberFunction ()을 작성해야하므로 클라이언트 코드가 다소 혼란스럽고 부적절합니다.

업데이트 : 귀하의 반응에 감사드립니다. 안타깝게도 제 질문에 답한 것 같습니다. 나는 그것과 함께 사는 법을 배워야 할 것 같다 ...


자신의 질문에 답하셨습니다. 정적 초기화 순서는 정의되어 있지 않으며 가장 우아한 방법은 (정적 초기화를 수행하는 동안, 즉 완전히 리팩토링하지 않는 동안) 함수에서 초기화를 래핑하는 것입니다.

https://isocpp.org/wiki/faq/ctors#static-init-order 에서 시작하는 C ++ FAQ 항목 읽기


전역 정적 변수가 너무 많이 필요한지 재고해야 할 수도 있습니다. 때때로 유용 할 수 있지만, 특히 일부 정적 변수가 다른 변수에 의존하는 경우 더 작은 로컬 범위로 리팩토링하는 것이 훨씬 더 간단합니다.

그러나 당신이 맞습니다. 특정한 초기화 순서를 보장 할 수있는 방법이 없습니다. 그래서 만약 당신의 마음이 그것에 설정되어 있다면, 당신이 언급 한 것처럼 초기화를 함수에 유지하는 것이 아마도 가장 간단한 방법 일 것입니다.


실제로 이것은 작동합니다. 유감스럽게도 globalObject.MemberFunction () 대신 globalObject (). MemberFunction ()을 작성해야하므로 클라이언트 코드가 다소 혼란스럽고 부적절합니다.

그러나 가장 중요한 것은 그것이 작동한다는 것입니다. 올바른 사용법을 우회하는 것은 쉽지 않습니다.

프로그램 정확성이 최우선 순위 여야합니다. 또한 IMHO, 위의 ()는 순전히 문체입니다. 전혀 중요하지 않습니다.

플랫폼에 따라 너무 많은 동적 초기화에주의하십시오. 동적 이니셜 라이저에 대해 수행 할 수있는 비교적 적은 양의 정리가 있습니다 ( 여기 참조 ). 멤버가 다른 전역 개체를 포함하는 전역 개체 컨테이너를 사용하여이 문제를 해결할 수 있습니다. 따라서 다음이 있습니다.

Globals & getGlobals ()
{
  static Globals cache;
  return cache;
}

프로그램의 모든 전역 개체를 정리하기 위해 ~ Globals ()를 한 번만 호출하면됩니다. 글로벌에 액세스하려면 여전히 다음과 같은 것이 있습니다.

getGlobals().configuration.memberFunction ();

정말로 원한다면 이것을 매크로로 감싸서 매크로를 사용하여 타이핑을 약간 줄일 수 있습니다.

#define GLOBAL(X) getGlobals().#X
GLOBAL(object).memberFunction ();

그러나 이것은 초기 솔루션의 구문상의 설탕 일뿐입니다.


대부분의 컴파일러 (링커)는 실제로 순서를 지정하는 (이동 불가능한) 방법을 지원합니다. 예를 들어 Visual Studio에서는 init_seg pragma를 사용 하여 초기화를 여러 그룹으로 정렬 할 수 있습니다 . AFAIK는 각 그룹 내에서 주문을 보장 할 방법이 없습니다. 이것은 휴대가 불가능하기 때문에 디자인을 필요로하지 않도록 수정할 수 있는지 고려할 수 있지만 옵션은 밖에 있습니다.


이 스레드의 나이를 무시하고 내가 찾은 해결책을 제안하고 싶습니다. 많은 사람들이 앞서 지적했듯이 C ++는 정적 초기화 순서를위한 메커니즘을 제공하지 않습니다. 내가 제안하는 것은 클래스의 정적 메서드 내부에 각 정적 멤버를 캡슐화하여 멤버를 초기화하고 객체 지향 방식으로 액세스를 제공하는 것입니다. 다른 멤버 중에서 "PI"를 포함하는 "Math"라는 클래스를 정의한다고 가정 해 보겠습니다.

class Math {
public:
   static const float Pi() {
       static const float s_PI = 3.14f;
       return s_PI;
   }
}

s_PI는 Pi () 메서드가 GCC에서 처음 호출 될 때 초기화됩니다. 참고 : 정적 저장소가있는 로컬 개체에는 구현에 따라 달라지는 수명주기가 있습니다. 자세한 내용은 6.7.4 in 2를 확인하세요 .

정적 키워드 , C ++ 표준


메서드에서 정적을 래핑하면 순서 문제가 해결되지만 다른 사람들이 지적한 것처럼 스레드로부터 안전하지는 않지만 문제가되는 경우 스레드로 만들 수도 있습니다.

// File scope static pointer is thread safe and is initialized first.
static Type * theOneAndOnlyInstance = 0;

Type& globalObject()
{
    if(theOneAndOnlyInstance == 0)
    {
         // Put mutex lock here for thread safety
         theOneAndOnlyInstance = new Type();
    }

    return *theOneAndOnlyInstance;
}

참고 URL : https://stackoverflow.com/questions/1005685/c-static-initialization-order

반응형