non-local static 객체 초기화 순서

non-local static 객체


non-local이란?,non-local이라는 용어는 사실 내가 effectivec++라는 책에서 배운 용어이다. 이 용어는 비함수 국부용역 내를 가리킨다. 그렇다면non-local static 대상은 무엇을 가리키는가?사실static(static 키워드가 정의한 대상이 아니다) 대상이라면 최소한 그 메모리가 더미와 창고에 있는 대상을 배제할 수 있다. 소위 static 대상은 데이터 세그먼트와bss 세그먼트에 저장된 대상을 가리킨다. 이런 대상은 전체 프로그램의 생명주기 내에 존재한다. 프로그램이 끝나지 않으면 계속 존재하고static 키워드를 이용하여 설명하는 대상은static 대상 중의 하나이다.그러나 함수 내부에서 정의된 static 대상이라면 이런 static 대상은local static 대상이라고 불린다. 이외에non-local static 대상이다. 예를 들어 글로벌 역할 영역 내의 static 대상,namespace 역할 영역 내의 static 대상, 클래스 역할 영역 내에서 static 키워드로 설명하는 대상이다.파일 역할 영역 내의static 대상 등. 지금까지non-local static 대상의 의미를 분명히 설명했을 거라고 믿습니다.

왜 이 얘기를 해요?


사실 저도 C++의 흰둥이입니다. 저는 책을 읽으면서 자신이 이해하지 못하거나 재미있고 중요한 지식을 가지고 실천과 정리를 통해 블로그를 만들었습니다. 사실 이 블로그의 주제는 effective C++(from item 4)에서 나온 것입니다. 왜 이 화제가 중요하다고 생각합니까?사실 C++가 배우기 어려운 이유 중 하나는 C++에 명확한 정의가 없는 부분이 많다고 생각합니다. 본고가 그 중 하나입니다. C++에서 서로 다른 컴파일러 단원에 정의된non-local static 대상에 대한 초기화 상대적인 순서는 명확한 정의가 없다고 생각합니다. 주요 원인은 그것들의 초기화 순서를 결정하는 데 상당히 어렵고 매우 어렵거나 전혀 이해가 없기 때문입니다. 왜 그런지 저도 잘 모르겠습니다.이것은 컴파일러를 하는 사람들이 해야 할 일이다. 우리는 이것이 해결되지 않은 버그라고 생각한다. 우선 컴파일러라는 용어의 의미를 설명하자. 컴파일러가 여기서 가리키는 것은 컴파일러를 해야 한다.cpp 파일, 하나.cpp 파일은 하나의 컴파일러 단위입니다. 만약 한 장면에서 두 개의 서로 다른 컴파일러 단위에 두 개의 static 변수가 존재하고 그 중 하나의static 변수가 다른 변수를 이용하여 초기화되었다면 이것은 정의되지 않은 것이 분명합니다. 두 개의 static 대상의 초기화 순서는 정의되지 않았기 때문입니다. 더욱 직관적으로 보기 위해서 다음과 같은 예를 들겠습니다.
first.cpp 파일
#include <iostream>
#include "common.h"
test1 t1;

second.cpp 파일
#include <iostream>
#include "common.h"
test2 t2;

last.cpp 파일
#include <iostream>
#include "common.h"
using namespace std;

int main()
{
    cout << "Hello World" << endl;
    return 0;
}

common.h 헤더 파일
#ifndef _LIB_H_
#define _LIB_H_

#include <iostream>

using namespace std;
class test2;
extern test2 t2;

class test2
{
    public:
        test2()
        {
        value = 100;
            cout << "test2 construct" << endl;
        }

        void said()
        {
            cout << "I am test2 " << "value=" << value << endl;
        }
    private:
    int value;
};


class test1
{
    public:
        test1()
        {
            cout << "test1 construct" << endl;
            t2.said();
        }
};
#endif

테스트 1과 테스트 2 두 종류를 정의했고 테스트 1에서 테스트 2 종류를 호출한 실례 t2.first.cpp 및 second.cpp는 각각 t1과 t2 두 실례의 초기화 작업입니다. 초기화 순서가 명확하지 않기 때문에 실행 결과가 정의되지 않았습니다. 다음은 실행 결과입니다.
#g++ -c -o first.o first.cpp 
#g++ -c -o second.o second.cpp 
#g++ -c -o last.o last.cpp 
#g++ last.o first.o second.o 
#./a.out 
test1 construct
I am test2 value=0
test2 construct
Hello World
#g++ last.o second.o first.o 
#./a.out 
test2 construct
test1 construct
I am test2 value=100
Hello World

우선 t1과 t2의 초기화는main 함수 이전에 이루어진 것이므로 사실first를 발견할 수 있습니다.o 및 second.o 컴파일링의 순서가 최종 출력 결과에 영향을 주었다.fisrt.o 이전에 t1이 초기화되고 t2가 초기화되지 않으면 t2가 먼저 초기화되고 t1이 초기화되기 시작합니다.value의 값을 통해 알 수 있습니다. 위의 예를 통해non-local static 대상에 존재하는 이 초기화 순서가 정의되지 않은 문제점을 증명했습니다.

이 문제를 해결하다


비록 C++에 대해 서로 다른 컴파일러 단원에 정의된non-local static 대상의 초기화 상대적인 순서는 명확한 정의가 해결되지 않았지만 다행히도 프로그래머들이 작은 디자인을 조금만 하면 이 버그를 완전히 제거할 수 있다. 본고의 마지막 부분은 바로 이 문제를 해결하는 것이다. local static를 이용하면 이 문제를 해결할 수 있다.이것은 local static 대상이 함수가 호출되는 동안 이 대상의 정의식을 처음 만났을 때 초기화되기 때문입니다. 읽기가 매우 까다롭지 않습니까?그래, 이 방법으로 위의 예를 개조해서 이 문제를 설명해라. 퍼스트.cpp는 변경 사항이 필요 없습니다.second.cpp를 다음과 같이 수정합니다.
//             ,        
test2& gettest()
{
    static test2 t2;
    return t2;
}

common.h 아래로 이렇게 수정
#ifndef _LIB_H_
#define _LIB_H_

#include <iostream>

using namespace std;
class test2;
test2& gettest();  //       
class test2
{
    public:
        test2():value(100)
        {
            //value = 100;
            cout << "test2 construct" << endl;
        }

        void said()
        {
            cout << "I am test2 " << "value" << value << endl;
        }
    int value;
};


class test1
{
    public:
        test1()
        {
            cout << "test1 construct" << endl;
            gettest().said(); //         t2   
        }
};
#endif

원래의non-local static 대상 t2는local static 대상이 되었다. local static 대상의 한 특성을 이용하여 컴파일할 때 자동으로 초기화되지 않고 함수를 호출할 때local static 대상이 정의될 때 초기화된다. 단례를 쓴 독자들은 이런 용법을 잘 알고 있을 것이다.단례적인 실현 방식 중 하나는 local static 대상을 이용하여 완성하면 프로그램의 시작 속도를 높일 수 있다는 것이다. 왜냐하면 local static 대상은 프로그램이 시작될 때 초기화되지 않고 사용할 때만 초기화되기 때문이다.

좋은 웹페이지 즐겨찾기