2014-03-27 2 views
3

내가 좋아하는 "초기화"클래스의 번호와 세계지도를CPP 파일은

std::map<long, std::string> Global_ID_Mapper; 

을 초기화하기 위해 노력하고있어 무시된다 애플리케이션 시작 중에 자동으로 매핑됩니다. 그래서 내 cpp 파일 중 하나에서 "init"클래스의 전역 변수를 정의합니다.

// AGlobalMapperInitializer.cpp 

AGlobalMapperInitializer AGlobalMapperInitializer_Value; 

매퍼 채우기는 AGlobalMapperInitializer_Value 작성의 부작용입니다.

문제는이 전역 변수를 제외하고 cpp에 아무 것도 포함되어 있지 않으면 링커에서 cpp를 명백히 무시한다는 것입니다. 유용한 일부 다른 코드를 cpp에 넣거나 (비어 있지 않은 일부 cpp에 전역 이니셜 라이저를 정의 할 때) 생성자가 호출되고 전역 매퍼가 채워집니다. 그러나 cpp가 다른 파일에서 참조되지 않는 전역 만 포함하는 경우 cpp가 컴파일되고 obj 파일에 변수가 들어 있지만 링커는 링크 중에이를 언급하지 않고 exe에서 빠뜨립니다.

어떻게하면 exe에 cpp를 연결하도록 고집 할 수 있습니까? 일부 pragma 또는 dummy 코드를 cpp에 입력하여 무시하지 않습니까? 나는 x 같은 파일 (실제로 번역 단위)로부터 함수 나 변수가 어느 참조하지 않을 경우 2012 년

+1

일반적인 대체 방법 중 하나는 처음 사용할 때 전역/싱글 톤을 초기화하는 것입니다. – MooseBoys

+0

(Dll) 전체 클래스 AGlobalMapperInitializer를 내보내고 클래스의 정적 멤버를 전역으로 만들거나 클래스 외부에서 extern (Dll) Export로 헤더에 전역을 선언 할 수 있습니다. (그렇지 않으면 전역은 트랜 슬 레이션 유닛의 로컬이고 최적화 됨) –

+0

링커는 참조되지 않은 모든 객체를 버립니다. 내보낼 수없는 내보내기를 선언하는 것 외에는 어떤 함수에서나이를 참조 할 수 있습니다. 컴파일러가'main() {printf ("", & AGlobalMapperInitializer_Value)}처럼이 참조를 최적화 할 수 없도록주의하십시오. }' – harper

답변

1

해결책을 찾는 데 도움이되는 각도 및 하퍼 모두에게 감사드립니다.

  1. 휴대용 일 (그러나 때문에 성능이 좋지 않은) :

    은이 가능한 해결 방법이 있습니다.

    이니셜 라이저 인스턴스는 전용 cpp 파일이 아니라 h에서 단어 static을 사용하여 정의 할 수 있습니다.

    // AGlobalMapperInitializer.h 
    // It wasn't mentioned before that this h file is included in many cpp files 
    struct AGlobalMapperInitializer 
    { 
        AGlobalMapperInitializer() 
        { 
         if(!Global_ID_Mapper.insert(std::make_pair(1, "Value1")).second) 
          return; 
         Global_ID_Mapper.insert(std::make_pair(2, "Value2")); 
        } 
    }; 
    
    static AGlobalMapperInitializer AGlobalMapperInitializer_Value; 
    

    변수가 static 때문에

    AGlobalMapperInitializer_Value은 시간의 파일을 포함하는 모든 CPP 파일에 별도로 작성됩니다. 이러한 각 변수는 전역 매퍼에 값을 추가하려고 시도하고 있습니다. 확실히 단 하나만 성공합니다. 첫 번째 삽입 결과를 확인하면 성능 문제가 부분적으로 해결됩니다. 첫 번째 값이 이미 삽입 된 경우 다른 값을 입력 할 필요가 없습니다.

    참고 :이 모든 인스턴스는 동일한 스레드 내에서 생성된다고 가정합니다. 그렇지 않으면 전역 매퍼가 삽입 호출 동기화를 구현해야합니다.

  2. 컴파일러 관련 솔루션 (Visual Studio).

    링커는 #pragma comment (linker, "/include:<decorated name>")을 추가하여 클래스를 유지해야 할 수 있습니다. 데코 레이팅 된 이름은 클래스 생성자 또는 다른 함수가 될 수 있습니다. 문제는 데코 레이팅 된 이름 하드 코드를 지정하는 것이 좋지도 편리하지 않다는 것입니다. 장식 방법은 컴파일러 업그레이드로 변경 될 수 있습니다. 여기서는 __FUNCDNAME__을 사용할 수 있습니다.

    struct AGlobalMapperInitializer 
    { 
        AGlobalMapperInitializer() 
        { 
         // Make sure the class will not be threw away by linker 
         #pragma comment (linker, "/include:"__FUNCDNAME__) 
    
         Global_ID_Mapper.insert(std::make_pair(1, "Value1")); 
         Global_ID_Mapper.insert(std::make_pair(2, "Value2")); 
        } 
    }; 
    

    다행히도 #pragma은 클래스 생성자 내에 지정할 수 있습니다.

2

C++가 자리를 차지할 전역 변수 x의 초기화를 필요로하지 않는 비주얼 스튜디오를 사용합니다.

보기 C++ 11 [basic.start.init]§4 :

그것은 구현 정의 정적 저장 기간과 비 로컬 변수의 동적 초기화 main의 제 문 전에 수행되는지 여부이다. 초기화가 main의 첫 번째 명령문 이후에 특정 시점으로 연기되는 경우 초기화 될 변수와 동일한 번역 단위에 정의 된 함수 또는 변수의 첫 번째 odr-use (3.2) 전에 발생해야합니다.

그래서 변수 초기화를 강제하려면 다른 내용을 실제로 사용하는 파일에 넣거나 어딘가에서 변수를 직접 사용해야합니다.

+0

아주 잘, 내 문제를 완전히 설명합니다. 'cpp에 무시할 수 있도록 일부 pragma 또는 dummy 코드가 있습니까? ' – Kunis

+0

@ user940014'#pragma's는 컴파일러에 따라 다르므로 컴파일러의 설명서를 참조하십시오 . "더미 코드"에 관해서는 제 대답이 옵션을 나열합니다 : vars를 사용하거나 사용하는 것과 함께 넣으십시오 ("다른 곳에 넣고 사용하십시오"). – Angew

+0

@Andew 나는 너를 쥐었다. 나는 다른 cpp를 바꾸는 것을 피할 수 없다? 제 말은, 심지어 첫 번째 cpp에 무언가 (더미 코드)를 넣어도이 더미 코드를 사용할 다른 cpp에 코드를 추가해야한다는 것입니다. – Kunis

1

링커에는 변수가 포함되지 않으며 참조되지 않을 때 이니셜 라이저입니다. 당신은 당신의 코드 내에서이 변수에 대한 참조를 만들 수 있습니다

int main() 
{ 
    printf("", &AGlobalMapperInitializer_Value)); 
} 

당신이 링커의 /INCLUDE 인수와 같은 효과를 일으키는 원인이되는 소스 코드의 오염을 방지합니다. 위의 해킹을 시도 할 때 .map 파일에서 가져올 수있는 데코 레이팅 된 이름을 추가해야합니다.

VS2010은 구성 속성 -> 링커 -> 입력의 프로젝트 속성에서 Force Symbol Reference이라는 옵션을 제공합니다. 나는 그것이 VS2012와 동일하길 바란다.

+0

감사합니다. 필자는'/ INCLUDE' 옵션을 데코 레이팅 된 이름과 함께 사용해야한다는 사실을 알지 못했습니다. 이제 hp 파일에'#pragma comment (linker, "/ include :? AGlobalMapperInitializer_Value @@ 3VAGlobalMapperInitializer @@ A")'를 추가하고 내가 원하는 것을 얻었습니다. 그러나이'#pragma'는 무시 된 cpp에 추가되면 작동하지 않습니다. – Kunis

+0

#pragma를 사용하면 소스 코드가 오염됩니다. 나는 이것을 프로젝트 속성에 숨기는 것을 고려할 것이다. ;-) – harper

+0

문제는 내가 최근 몇 exe로 컴파일되는 정적 라이브러리의 번호가 있다는 것입니다. lib의 프로젝트에서'심볼 참조를 강제로 '변경하면 도움이되지 않습니다. 어쨌든 심볼은 링커에 의해 던져지기 위해서 마지막으로 링크 된 프로젝트의'심볼 참조 참조 '를 변경해야합니다. 하지만 lib의 모든 수준을 lib 수준으로 유지하려고합니다. 게다가, 나는 lib를 링크하는 프로젝트에 접근 할 수 없다. 나는 바꿀 것이다. 내가 발견 한 유일한 방법은'#pragma'입니다. 또한'__FUNCDNAME__'을 사용하여 데코 레이팅 된 하드 코드를 지정하는 것을 피할 수 있습니다. – Kunis