문제

C ++는 컴파일 장치 (.CPP 파일)의 변수가 선언 순서대로 초기화되도록 보장합니다. 컴파일 단위의 수에 대해이 규칙은 각각 각각에 대해 별도로 작동합니다 (클래스 이외의 정적 변수를 의미합니다).

그러나 변수 초기화 순서는 다른 컴파일 단위에서 정의되지 않습니다.

GCC 및 MSVC에 대한이 순서에 대한 설명을 어디에서 볼 수 있습니까 (이에 의존하는 것은 매우 나쁜 아이디어라는 것을 알고 있습니다. 새로운 GCC 메이저 및 다른 OS로 이동할 때 레거시 코드로 가질 수있는 문제를 이해하는 것입니다). ?

도움이 되었습니까?

해결책

당신이 말했듯이, 주문은 다른 편집 장치에서 정의되지 않습니다.

동일한 컴파일 장치 내에서 순서가 잘 정의되어 있습니다. 정의와 동일한 순서.

이것은 언어 수준이 아니라 링커 수준에서 해결되기 때문입니다. 따라서 링커 문서를 확인해야합니다. 나는 이것이 유용한 방식으로 도움이 될 것이라고 정말로 의심합니다.

GCC의 경우 : 확인하십시오 LD

연결중인 객체 파일의 순서를 변경하더라도 초기화 순서가 변경 될 수 있습니다. 따라서 걱정해야 할 것은 링커뿐만 아니라 빌드 시스템에서 링커가 어떻게 호출되는지입니다. 문제를 해결하려고 시도조차도 실제로 초보자입니다.

이것은 일반적으로 자신의 초기화 중에 서로를 참조하는 글로벌을 초기화 할 때만 문제가됩니다 (따라서 생성자가있는 객체에만 영향을 미칩니다).

문제를 해결하는 기술이 있습니다.

  • 게으른 초기화.
  • 슈워츠 카운터
  • 모든 복잡한 글로벌 변수를 동일한 컴파일 장치 내에 넣으십시오.

  • 참고 1 : 글로벌 :
    잠재적으로 초기화 된 정적 저장 기간 변수를 언급하기 위해 느슨하게 사용되었습니다. main().
  • 참고 2 : 잠재적으로
    일반적인 경우 우리는 정적 저장 기간 변수가 메인 전에 초기화 될 것으로 예상되지만 일부 상황에서는 컴파일러가 초기화를 연기 할 수 있습니다 (규칙은 자세한 내용은 표준 참조).

다른 팁

모듈 사이의 생성자 순서는 주로 객체를 링커로 전달하는 순서의 함수라고 기대합니다.

그러나 GCC가 당신을 허락합니다 사용 init_priority 주문을 명시 적으로 지정합니다 글로벌 CTORS :

class Thingy
{
public:
    Thingy(char*p) {printf(p);}
};

Thingy a("A");
Thingy b("B");
Thingy c("C");

예상대로 'ABC'를 출력하지만

Thingy a __attribute__((init_priority(300))) ("A");
Thingy b __attribute__((init_priority(200))) ("B");
Thingy c __attribute__((init_priority(400))) ("C");

출력 'BAC'.

절대적으로 필요하지 않는 한이 정보에 의존해서는 안된다는 것을 이미 알고 있기 때문에 여기에 있습니다. 다양한 도구 체인 (MSVC, GCC/LD, Clang/LLVM 등)에서의 일반적인 관찰은 객체 파일이 링커로 전달되는 순서가 초기화 될 순서라는 것입니다.

이것에 대한 예외가 있으며, 나는 그들 모두에게 주장하지는 않지만 여기에 내가 나 자신에게 달려있는 것들이 있습니다.

1) 4.7 이전의 GCC 버전은 실제로 링크 라인의 역 순서로 초기화됩니다. GCC 의이 티켓 변경이 일어 났을 때, 초기화 순서 (광산 포함)에 의존하는 많은 프로그램이 깨졌습니다.

2) GCC 및 Clang에서 사용 생성자 기능 우선 순위 초기화 순서를 변경할 수 있습니다. 이것은 "생성자"라고 선언 된 함수에만 적용됩니다 (즉, 글로벌 객체 생성자처럼 실행되어야합니다). 나는 이와 같은 우선 순위를 사용하려고 시도했지만 생성자 함수에서 우선 순위가 가장 높으면 우선 순위가없는 모든 생성자 (예 : 일반적인 글로벌 개체, 우선 순위가없는 생성자 함수)가 초기화된다는 것을 발견했습니다. 첫 번째. 다시 말해, 우선 순위는 우선 순위가있는 다른 기능과 관련이 있지만 실제 일등석 시민은 우선 순위가없는 사람들입니다. 더 나쁘게하기 위해,이 규칙은 위의 (1)로 인해 4.7 이전에 GCC의 효과적으로 반대입니다.

3) 창에는 매우 깔끔하고 유용한 공유 라이브러리 (DLL) 진입 기능이 있습니다. dllmain (), 정의 된 경우 모든 글로벌 데이터가 초기화 된 후 바로 DLL_PROCESS_ATTACH와 동일한 매개 변수 "FDWRISANG"으로 실행됩니다. ~ 전에 소비 애플리케이션은 DLL에서 모든 기능을 호출 할 수 있습니다. 이것은 경우에 따라 매우 유용하며 절대적으로 아니다 C 또는 C ++가있는 GCC 또는 Clang을 가진 다른 플랫폼에서 이와 유사한 동작. 가장 가까운 것은 우선 순위를 가진 생성자 기능을 만드는 것입니다 (위의 점 (2) 참조). 이는 절대적으로 동일하지 않으며 dllmain ()가 작동하는 많은 사용 사례에 대해서는 효과가 없습니다.

4) CMAKE를 사용하여 자주 빌드 시스템을 생성하는 경우 입력 소스 파일의 순서가 링커에 제공된 결과 객체 파일의 순서가 될 것임을 알게되었습니다. 그러나 종종 귀하의 응용 프로그램/DLL은 다른 라이브러리에서도 링크하는 경우가 있습니다.이 경우 해당 라이브러리는 링크 라인에 있습니다. ~ 후에 입력 소스 파일. 당신이 당신의 글로벌 객체 중 하나를 원한다면 첫 번째 초기화하려면 운이 좋으며 해당 개체가 포함 된 소스 파일을 소스 파일 목록에서 첫 번째로 넣을 수 있습니다. 그러나 만약 당신이 하나를 갖고 싶다면 아주 마지막 초기화 (DLLMAIN () 동작!)을 효과적으로 복제 할 수 있으려면 해당 소스 파일을 사용하여 add_library ()를 호출하여 정적 라이브러리를 생성하고 결과 정적 라이브러리를 Target_Link_Libraries에서 마지막 링크로 추가 할 수 있습니다. ) 응용 프로그램/DLL을 요청하십시오. 이 경우 글로벌 객체가 최적화 될 수 있으며 -whole-archive 링커가 해당 특정 작은 아카이브 파일에 사용되지 않은 기호를 제거하지 않도록 강제로 플래그.

닫기 팁

링크 된 응용 프로그램/공유 라이브러리의 결과 초기화 순서를 절대적으로 알기 위해 -Print-Map to Ld Linker 및 .init_array (또는 4.7 이전의 GCC, .CTORS 용 GREP)의 GREP를 통과하십시오. 모든 글로벌 생성자는 초기화되도록 순서대로 인쇄되며 4.7 이전에 GCC의 순서가 반대임을 기억합니다 (위의 지점 참조).

이 답변을 작성하기위한 동기 부여 요인은이 정보를 알아야한다는 것입니다. 다른 선택은 초기화 순서에 의존하는 것 외에 다른 선택이 없었으며, 다른 게시물과 인터넷 포럼 에서이 정보의 희소 한 부분 만 발견했습니다. 그것의 대부분은 많은 실험을 통해 배웠으며, 이것이 일부 사람들이 그렇게 할 시간을 절약하기를 바랍니다!

http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12 - this link moves around. this one is more stable but you will have to look around for it.

edit: osgx supplied a better link.

In addition to Martin's comments, coming from a C background, I always think of static variables as part of the program executable, incorporated and allocated space in the data segment. Thus static variables can be thought of as being initialised as the program loads, prior to any code being executed. The exact order in which this happens can be ascertained by looking at the data segment of map file output by the linker, but for most intents and purposes the initialisation is simultaeneous.

Edit: Depending on construction order of static objects is liable to be non-portable and should probably be avoided.

If you really want to know the final order I would recommend you to create a class whose constructor logs the current timestamp and create several static instances of the class in each of your cpp files so that you could know the final order of initialization. Make sure to put some little time consuming operation in the constructor just so you don't get the same time stamp for each file.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top