3

다른 모듈에 정의 된 배열의 셀을 초기화하려는 특정 솔루션을 고려하고 있습니다 (하나의 테이블을 초기화하는 많은 모듈이 있음). main을 실행하기 전에 배열을 읽지 않습니다 (따라서 정적 초기화 순서에는 문제가 없습니다).다른 모듈에 정의 된 변수를 부분적으로 초기화하십시오.

내 접근 방법 : 생성자는 부작용이 있기 때문에

/* secondary module */ 

extern int i[10]; // the array 

const struct Initialize { 
    Initialize() { i[0] = 12345; } 
} init; 


/* main module */ 

#include <stdio.h> 


int i[10]; 

int main() 
{ 
    printf("%d\n", i[0]); // check if the value is initialized 
} 

는 컴파일러가 init 일정을 제거하지 않습니다. 내가 맞습니까? 메커니즘은 괜찮습니까? GCC (-O3)에서는 모든 것이 잘됩니다.

// 편집
현실 세계에는 많은 모듈이 있습니다. 나는 여분의 모듈을 피하기를 원한다. (더 나은 확장 성을 위해서) 모든 부 초기화 루틴을 모을 중심 장소. 따라서 각 모듈이 자체 초기화를 트리거하는 것이 중요합니다.

+0

각 모듈을 초기화하는 동안 i [] 배열이 이미 할당되어 있다고 가정합니다 (초기화되지 않음). –

+0

AFAIK 정적 저장 공간은 응용 프로그램이 시작될 때 한 단계에서 할당되고 0으로 지정됩니다. – adf88

+0

UP : 약 ** 글로벌 ** 정적 저장 공간 – adf88

답변

3

이것은 MSVC 컴파일러에서 작동하지만 GNU C++에서는 (적어도 저에게는) 적합하지 않습니다. GNU 링커는 컴파일 유닛 밖에서 사용되지 않는 모든 심볼을 제거합니다. 그런 초기화를 보장하는 유일한 방법은 "init once"관용구입니다. examle의 경우 :

init_once.h :

template <typename T> 
class InitOnce 
{ 
    T *instance; 
    static unsigned refs; 
public: 
    InitOnce() { 
     if (!refs++) { 
      instance = new T(); 
     } 
    } 

    ~InitOnce() { 
     if (!--refs) { 
      delete instance; 
     } 
    } 
}; 
template <typename T> unsigned InitOnce<T>::refs(0); 

unit.h :

는 secondary.cpp
#include "init_once.h" 

class Init : public InitOnce<Init> 
{ 
public: 
    Init(); 
    ~Init(); 
}; 
static Init module_init_; 

: 당신이 배열을 사용하는 이유

#include "unit.h" 
extern int i[10]; // the array 

Init::Init() 
{ 
    i[0] = 12345; 
} 
... 
+0

수락되었습니다. 그렇다면 내가하려는 것은 불가능합니다. 초기화 장치는 장치 외부에서 어떻게 든 참조되어야합니다. – adf88

0

편집

/*secondary module (secondary.cpp) */ 

    int i[10]; 
    void func() 
    { 
     i[0]=1; 

    } 

.

/*main module (main.cpp)*/ 

    #include<iostream> 

    extern int i[]; 
    void func(); 
    int main() 
    { 
    func(); 
    std::cout<<i[0]; //prints 1 
    } 

컴파일, 일반적으로 생성자에서 g++ secondary.cpp main.cpp -o myfile

는 클래스의 멤버를 초기화에 사용되는 (그리고 사용한다)를 사용하여 링크를 작성하고 실행.

+0

한 가지 중요성이 있습니다. 테이블의 셀을 초기화하고 싶지 않습니다. 내 예제를 편집하여 코드에 표시되도록했습니다. – adf88

+0

@ adf88 : 내 게시물을 편집했습니다. –

+0

나는 내 게시물도 편집했다. 나는 "모듈 내부에서 초기화"라고 쓰고 싶었다. – adf88

0

메인 모듈에 extern int i[10];을 넣지 않을 것이라고 생각합니다.하지만 adf88.

0

이 방법은 효과가있을 수 있지만 위험합니다. 단일 모듈 내의 전역/정적 생성 순서는 정의되지 않으며 모듈로드 순서도 지정됩니다 (명시 적으로 관리하지 않는 한). 예를 들어, secondary.c Initialize()가 실행되는 동안 i가 이미 있다고 가정합니다. 두 모듈이 동일한 공통 데이터를 초기화하지 않도록주의하거나 두 모듈이 부작용이 겹치는 초기화를 수행하도록주의해야합니다.

필자는 공통 데이터의 소유자 (메인 모듈)가 데이터 초기화를 수행하는 인터페이스를 사용하여 공용 데이터의 소유자에게이를 글로벌 싱글 톤으로 공개하는 것이 필요하다고 생각합니다. init-order를 제어 할 수있는 중심적인 위치를 가지며, (중요한 섹션이나 기타 동시성 프리미티브를 사용하여) 동시 액세스를 제어 할 수도 있습니다. 당신의 간단한 예의 라인을 따라, 그 수 있습니다 -

/주 모듈 (main.c를)/

사용법 #include 클래스 CommonDat { INT I;

public: 
    const int GetI() { return i;} 
    void SetI(int newI) { i = newI; } 
    void incI()   
    { 
     AcquireSomeLock(); 
     i++; 
     ReleaseTheLock(); 
    } 
} 

CommonDat g_CommonDat; 
CommonDat* getCommonDat() { return &g_CommonDat; } 

int main(void) 
{ 
    printf("%d",getCommonDat()->GetI()); 
} 

은 보조 제어 모듈의 실행 시간 (및 글로벌 c'tors 동안 하지 통과)에서, 이러한 인터페이스를 호출하는 것도 바람직이다.

(참고 : 파일의 이름을 C 파일로했지만 질문에 C++로 태그를 지정했습니다. 물론 추천 코드는 C++입니다.)

+0

필자가 "어레이가 메인을 실행하기 전에 읽혀지지 않을 것"이라고 썼듯이 초기화 순서에 문제가 없다. 그리고 나는 중앙의 장소를 초기화하는 것을 원하지 않는다. 나는 각각의 부 초기화가 관련된 모듈로부터 트리거되기를 원한다. – adf88

+0

이것은 초기화 명령 문제 일뿐만 아니라 2 차 모듈 초기화 중 어레이가 심지어 할당 * 될 것을 보장 할 수 있습니까? –

+0

단일 변환 단위 내에서 초기화 순서는 3.6.2에 따라 잘 정의됩니다. 나는 당신이 '모듈'이라고 부르는 것을 확신하지 못한다. - 이것은 더 세밀한 입상 수준 ('모듈'> 번역 단위를 가정 함)에 대한 의견 일 뿐이다. –

0

내가 물어 봐도 (실행 경계가 벗어날 위험이 있습니다.) std::vector을 사용할 수 있습니까?

std::vector<int>& globalArray() 
{ 
    static std::vector<int> V; 
    return V; 
} 

bool const push_back(std::vector<int>& vec, int v) 
{ 
    vec.push_back(v); 
    return true; // dummy return for static init 
} 

이 배열은 함수를 처음 호출 할 때 지연 초기화됩니다.

당신은 같이 사용할 수 있습니다

// module1.cpp 
static bool const dummy = push_back(globalArray(), 1); 

// module2.cpp 
static bool const dummy = push_back(globalArray(), 2); 

그것은 훨씬 더 쉽게 적은 것 같다 오류가 발생하기 쉬운. C++ 0x가 될 때까지 멀티 쓰레드 호환이 아닙니다.

+0

그것은 중요한 것이 아닙니다. 그러한 위험이 없을 수도 있습니다 ... – adf88

+0

위험이 없다면 모듈이 이미 단단히 결합되어 있습니다 (즉, 어떤 색인을 작성해야하는지 알 필요가 있음).이 경우에는 단일 소스 파일은 인덱스를 실제로 확인할 수 있으므로 한눈에 알 수 있습니다. 내 요점은 디커플링에 관한 것이었다. –

관련 문제