Kevin Dominic의 Studying Rock Drill~

STL Violation for VC++ 6.0 본문

이야기거리/개발자 뒷담화

STL Violation for VC++ 6.0

Kevin Dominic 2010. 6. 29. 15:27
요즘들어서야 STL 쓰는 재미에 푹 빠져 살고 있습니다.
사실 옛날부터 STL에 대해서는 알고 있었지만, 막상 쓸 필요성을 못 느꼈기 때문입니다.
상용화된 프로그램을 개발하시는 분들이야 늘상 몸에 붙이고 다니셔야 할 분들이시지만(저도 언젠가는 그렇게 되겠지만)
학생이라 쓰고 취업준비생이라 읽는 저같은 사람은, STL을 쓸만큼의 대형 프로젝트를 만질 기회도 흔치 않고(사실 웬만한 것은 동적 배열로 해결이 가능했기 때문입니다), 사소한 곳에 STL을 쓰자니 편해지긴 하겠지만, 배열과 포인터에 대한 감각(?)이 떨어질 것 같다는 말도 안되는 느낌 때문에 STL을 꺼려하고 있었습니다.

그런데 최근에 그래픽스 엔진을 만들고, 입사코자 하는 회사에 포트폴리오로 제출하면서부터 점점 빠른 개발과 업데이트가 필수 항목이 되어버렸습니다. 다른 분들은 포트폴리오를 어떻게 제출하시는지 모르지만, 저는 표준 포트폴리오를 만들고, 회사마다 조금씩 특색있는 구상을 맞추어 제출하기 때문에 회사마다 포트폴리오가 조금씩은 다릅니다. 게다가 radiosity와 같은 최신기법(?)을 realtime으로 다루고자 하니 그래픽 자원이 모자란 환경에 맞추기 위해서도 매번 코드가 달라져야 해서, 배열과 포인터를 붙잡고 씨름하기에는 시간이 촉박해졌습니다.(그래서 열심히 노력한 끝에 P4 2.8Ghz, AGP 256MB 환경에서도 평균 150fps 정도를 찍고 있는지 모르겠습니다. 램이 2GB가 있다는 사실은 조금 빼고싶지만^^;;)

다른 분들도 <list> <vector> <iterator>등은 헤더파일에 많이 인클루드 하시고, 알게 모르게 많이 쓰실 것 같습니다. 특히 iterator같은 경우는 최근 각 회사들이 강조하는 디자인 패턴과도 연결이 되어있기 때문에 필수로 쓰게되는데요. 저도 요즘 이런 것들의 덕을 톡톡히 보는 중이었습니다.

문제는 오늘 발생했습니다.
매번 다른 종류의 delimeter가 있는 xml을 parsing할 때마다 클래스를 상속받거나 새로 만드는 것이 귀찮아서 Common class를 만들고자 했습니다. 예를 들어서 인터페이스만을 보여드린다면 다음과 같은 형태가 될 것입니다.(실제로 비슷한 구성을 띄게끔 했습니다)
class CXMLCommonParser
{
public:

   AttachBranchNode(...);
   SearchBranchNode(...);

   AttachItemInNode(...);
   SearchItemInNode(...);

private:
...
};


아마 xml data의 delimeter는 다음과 같은 형태로 주어질 것입니다.
실제 제가 게임 레벨 에디터를 만들기 위해 작성한 XML 초안입니다.
<?xml version="1.0" ?>
    <stages count="4">
        <stage name="Mars" number="0" mapsizex="15" mapsizey="13" levels="3">
            <level value="0" staticscount="7" dynamicscount="6" triggerscount="5">
                <statics>
                    <static object="1" startx="1400" starty="1200" endx="1470" endy="1270" />
                    <static object="17" startx="1000" starty="1000" endx="1200" endy="1200" />
                    <static object="20" startx="600" starty="1400" endx="700" endy="1600" />
                    <static object="20" startx="1800" starty="1800" endx="1900" endy="2000" />
                </statics>
                <dynamics>
                    <dynamic object="4" max="7" />
                    <dynamic object="3" max="5" />
                    <dynamic object="10" max="2" />
                </dynamics>
                <triggers>
                    <trigger mission="1" times="15000" condition1="0" condition2="5000" />
                    <trigger mission="2" times="45000" condition1="3" condition2="8" />
                    <trigger mission="2" times="45000" condition1="11" condition2="5" />
                </triggers>
            </level>
        </stage>
    </stages>

제가 원하는 방식의 파서는 위의 xml 파일이 있다고 가정한다면
AttachBranch(SearchBranch("stages"), "stage") <-- stages branch안에 stage branch를 트리구조 형태로 집어넣는...
위와 같은 인터페이스 함수 몇개만 부르고, Parsing하면 자동으로 모든 delimeter를 추출해 주는 형태의 클래스를 만들고 싶었던 것입니다.(귀차니즘의 극치^^;;) 그런데 std::list<...> XXX에 제가 원하는 변수는 다 들어갔는데, iterator 패턴으로 verbose 출력(수다쟁이(?), Dump!!)을 해보고자 하니 Access Violation error가 뜨면서 프로그램이 죽어버리는 것이었습니다.

XML Parser는 DOM과 SAX Parser로 나눌 수 있는데, 일단 저는 SAX Parser를 구현하기 위해 순차적으로 branch들을 읽어야 합니다. 그런데 위의 파일을 보시면 <statics>와 <dynamics> branch는 서로 같은 레벨에 있습니다. 프로그램이 죽는 곳을 찾아보니 하향식 레벨 생성에는 문제가 없는데, 같은 레벨의 객체를 붙이고서(생성까지는 제대로 되었더란 말입니다) iterator search를 하니 에러가...

원인을 찾아보니 다음과 같은 웹문서가 돌아다닙니다.
출처 : http://support.microsoft.com/kb/q172396/   <-- 기계번역된, 하지만 그래도 일단 믿고(??) 가야만 하는 사이트

VC++ 6.0에서 stl template 객체들은 가끔씩 임의의 정적 객체를 사용하여 프로그래밍이 되어 있는데, 특정 영역에서(무서워~ 거기가 어디인 줄 어떻게 알아...ㅠㅠ) dll, exe 사용시 정적 객체를 임의로 동적 복사하려는 행위를 하려한다는 것입니다. (무슨 뜽금없는 소리인지 모르는 번역투의 말투)

출처 : http://snaiper.tistory.com/25   <-- 이 분의 사이트가 저보다 더 자세한 상황 설명이 되어 있습니다.

  다른 분의 글을 참조해 보니 싱글코어가 아닌 듀얼코어 이상의 경우 template 구현에 사용된 일부 정적 객체가 유일성을 보장받아야 하는데, VC++ 6.0은 전형적인 싱글코어 때 개발이 되었기 때문에 멀티스레드 혹은 멀티코어에서 유일성을 보장하지 못하는 일부 코드가 들어가 있다는 뜻으로 이해를 할 수 있었습니다.(Double Locking Check 패턴이 사용되지 않았기 때문으로 추산됨)

이거이거... 갑자기 열심히 쓰고 싶은 마음이 싹 사라지는... 웬지 초치는 느낌이 듭니다(ㅡㅡ;;)