STL에 대한 논란: 아는 만큼 보인다. by object

어떻게 보면 유익하기도, 어떻게 보면 시간 낭비일 수도 있는 글타래:
안녕하세요^^ STL은 항상 논란거리인것 같습니다^^;

솔직히 STL을 빡시게 쓴 적이 얼마되지 않는다. 과거 회사에서 작업한 코드들은 100% 윈도우 기반이었고, 마침 MFC 7.0부터 도입된 MFCATL 라이브러리가 사용하기 너무 좋아서 계속 이 녀석을 사용했다. 예전 MFC collection 에 없던 Red-black tree도 추가되었고, 특정 타입의 여러 행동을 정의하는 Traits (일종의 functor 같은 것)도 사용하기가 무척 쉬웠다. CString이나 CList와는 달리 CAtlString과 CAtlList는 의존성도 약해서 non-MFC 코드에도 쉽게 사용할 수 있다. 무엇보다 소스를 이해하는데도 전혀 부담이 없었고 팀원들도 사용하는데 어려움이 없었다. 내가 주로 만들었던 프로그램은 게임 서버와 같은 성격은 아니고 패키지용 소프트웨어라서 그런지 STL을 써야한다는 그런 주변의 이야기도 잘 듣지 못하였다.

어차피 최적의 속도를 위해서는 포인터 기반의 자료구조 자체가 쥐약이다. 포인터 기반의 리스트, 트리, 혹은 그래프를 순회하는 경우를 흔히 pointer chasing이라고 부른다. 순회를 하는 과정이 새로운 주소로 점프하는 과정이라 캐쉬 미스를 엄청 유발한다. 그래서 정말 성능 크리티컬한 상황이라면 최대한 locality를 높일 수 있는 자료구조로 만들어야 한다.

나도 STL의 난해한 소스코드와 짜증났던 iterator 패턴 때문에 STL을 좋아하지 않았다. for 문이 두 줄 이상으로 나뉘어야 하는 경우가 다반사다. ::iterator를 쳐야하는 삽질은 typedef로 최대한 막으면 되지만 항상 타입을 맞춰야 하는 것이 귀찮기는 하다. 여전히 pair의 first, second와 같은 작명 센스는 맘에 들지 않는다. empty라는 메소드가 '비우다'라는 동사로서의 empty가 아니라 IsEmpty라는 성격인 것도 헷갈리기 딱 좋다. string 객체를 부득이하게 printf로 찍어야 하는 경우, .c_str()을 부르지 않아 삽질을 계속한다. 플랫폼마다 map의 이터레이터 구현이 달라 삽질한 경우도 있다.

 

그러나 쭉 써보면 이런 설계에 고개가 끄덕여진다. algorithm이나 functional에 있는 것들을 쓰면서 "내가 참 뭘 몰라도 한참 모르고 STL을 욕했네" 라는 반성이 들면서 다시 C++ 책을 봐야겠다는 생각이 든다. 과거 삽질을 해서 짰던 코드들을 이렇게 표현할 수도 있구나라고 깨닫고 있는 중이다. 그런 깨달음이 여러 경우 있었는데 말하면 나의 무식이 탄로날 것 같아 그냥 넘어가겠다.

더 현실적인 이유를 대자면, STL이 바보 같다고해서 자신이 직접 자료구조를 만들었다 하자. 내가 장담컨데, 전혀 획기적으로 새로운 자료구조가 아닌 이상, 이건 99% 삽질이다. 무시하는 것 처럼 들려도 하는 수 없다. 당신이 만든 자료구조가 STL보다 더 안전하고 더 빠르게 돌아가기를 기대하는 것이 쉽지 않다. STL이 완벽하지는 않지만 그렇다고 당신이 만든 자료구조도 완벽하지 않다.

어렸을 때는 MFC의 Doc/View 구조가 너무 짜증났었다. 왜 저렇게 불필요한 추상화를 둬서 더 복잡하게 하느냐고. 그래서 저거 다 날리고 직접 날 코딩했다. 그러다가 좀 복잡한 프로그램을 짜면서 나름대로 추상화를 하고 그러다보니 결국 MFC Doc/View 구조 비슷하게 흘러가는 것을 보고 MFC 설계자를 욕했던 나 자신을 반성한 적이 있었다. 여전히 Doc/View는 잘 안쓰지만 그것에 깔린 설계 철학은 훌륭하고 본 받을만 하다.

 

그러니까 결국 아는 만큼 보인다. 중학교 때였나 BASIC만 쓰다가 처음 C코드를 보고 도대체 #, ; 이런 괴상한 기호들이 왜 붙는거야? 라고 투덜거렸던 기억이 떠오른다.

 

추가.

#1. 위에서 string을 출력하는데 .c_str()을 호출하지 않아 삽질했다고 했다. 예를 들어, 아래 m_nameRTN이라는 변수는 STL string 타입이고 이걸 printf의 "%s"로 출력하고 싶다고 하자. string 객체는 묵시적인 const char*로의 변환이 없다. 반면, MFC/ATL의 CString은 이 캐스팅이 함축되어있어 그냥 클래스 객체를 날려도 문제가 없다. 아쉽게도 VC++ 컴파일러는 이런 경우 어떠한 warning을 만들어내지 않는다. 반면, 인텔 알바해서 자꾸 인텔 제품 광고하는 것 처럼 보이는데, 정말 컴파일러는 인텔 C/C++ 컴파일러가 gcc, VC++ 컴파일러보다 좋다. 특히 아래와 같은 경우에도 친절히 warning을 띄어준다. 게다가 에러가 난 column 위치까지 잡아준다. 너무 맘에 들어!!!!!! (자바나 C#는 원래부터 되는건데..) 인텔 C/C++ 컴파일러 for Windows는 비주얼스튜디오 전 버전에 아주 찰싹같이 달라붙어 사용하기 무지 편하다. 윈도우 버전은 돈 주고 사야하는 것이 좀 단점이지만... 트라이얼은 가능. (수정: 이 printf 출력 경우는 const char*로의 캐스팅이 일어나는 것이 아니라 MFC/ATL의 CString 객체의 첫번째 데이터가 char* 변수라서 제대로 표현이 되는 것입니다.)

Compiling with Intel(R) C++ 10.1.022 [IA-32]... (Intel C++ Environment)
Function.cpp
Function.cpp(165): warning #1595: non-POD (Plain Old Data) class type passed through
ellipsis
fprintf(g_outLoopDiscovery, "%s: %d BBs found.\n", m_nameRTN, m_numBB);
^

#2. template으로 많은 타입에 대해 instantiation이 되어 code bloat을 우려하는 대목도 있었는데, 요즘 컴파일러 그렇게 바보가 아니다. int, UINT32 같은 타입에 대해 중복된 템플릿 코드가 생성되어 있어도, whole program 최적화 (=IPO)로 동일한 코드들은 아예 하나로 합쳐 버린다.

#3. 그래도 때론 STL 소스코드가 MFCATL 컬렉션 소스처럼 좀 보기가 편했으면 얼마나 좋을까라는 생각은 해본다. 이제는 자꾸 들여다보니 좀 익숙해졌다만... 난 템플릿 공부를 <atlcoll.h>에 있는 코드를 보고 꽤 많이 했다.

#4. 많은 사람들이 "표현"에 굉장히 집착하는 것 같다. STL이 욕 먹는 주요한 이유 중 하나가 코드가 이쁘지 않아서 그렇다는 것인데 물론 나도 코드 표현에 집착하던 때가 있었다.


핑백

덧글

  • xeraph 2008/07/09 15:53 # 답글

    그래서 말이지만 C++는 언어 자체로 공부할게 너무 많다는게 불평이 나오는 원인인 듯 합니다. ㅋㅋ 라이브러리 다 포함한 것도 아니고 언어 명세만 집중해서 설명해도 베개 두께가 쉽게 나와버리니 원.. 그러니 공부하기는 싫고 잘 모르니 저런 얘기가 끊임없이 나오는게 아닌가 하네요.

    예전에도 게임 쪽에 있는 사람이 무려 vector를 초기값도 안 잡아놓고 요소를 추가할 수록 느려진다고 자기 자료구조랑 성능 비교해보라고 까는 글 보고 식겁해서 싸우다가 말이 안 통해서 그냥 포기했었죠 -_-
  • rein 2008/07/09 15:54 # 삭제 답글

    STL이랑 boost를 처음엔 진짜 왜 쓰나 싶었는데(...), 보면 볼수록 매력적인 설계가 많이 보여서 Orz 하고 있습니다; 알려면 많이 봐야하고, 많이 삽질해보는 수밖에 없는데, 저 스레드 시작한 분은 뭔가 좀 자기 코드에 빠져서 사는것같아서 -_-a
  • object 2008/07/09 21:31 #

    제가 볼 땐 그 분 자살골을 단단히 넣은 것 같습니다...
  • object 2008/07/09 15:59 # 답글

    프로그래밍 하는 사람들이 가장 빠지기 쉬운 오류가 자기가 짠 코드 보면서 자아도취에 빠지는 겁니다. 그러기가 정말 쉽죠. 그래서 gpgstudy 분위기가 ... 게임프로그래머되는데 대학 공부가 뭐 필요있냐.. 그런 분위기가 있는 것 같기도 하고. 프로그래밍은 정말 해보면 자기가 공부는 못 하더라도 프로그래밍은 잘 할 수 있을 거라는 착각이 들기에 딱 좋습니다. 일단 눈에 돌아가는게 보이니.

    이 런 말 하면 욕 먹으려나요. 전 프로그래밍 언어가 너무 쉬워질 필요는 없다고 봐요. 교량 설계하는데 필요한 지식이 학원에서 뚝딱 6개월 배운다고 되는게 아니잖아요. 프로그래밍도 좀 많더라도 학습량이 필요한 것은 나쁘지 않고 오히려 그렇게 해야 진입 장벽도 어느 정도 만들고 프로그래머라는 직업도 조금이나마 전문성을 가지지 않을까 생각해요. 이거 뭐 프로그래머가 학원에서 6개월 배우면 다 되는 것으로 오인되니 어떻게 프로그래머가 많은 돈을 벌고 안정적인 직업이 되겠습니까. 쩝..
  • nineye 2008/07/16 13:59 # 삭제

    프로그래밍 언어는 지금만으로도 충분히 쉽지가 않습니다. 물론 목표를 어떻게 잡냐가 중요한데.. 예를 들면, 난 stl이나 boost라이브러리보다 더 성능이 뛰어나고 잘 설계된 프로그램을 개발할 것이다... 라는 것을 목표로 삼는 다면 정말 어렵겠죠...ㅋ 그리고 stl이나 boost라이브러리에 대해 이해하고도 자신의 코드에 자아도취 된다면 충분히 그럴 자격이 있다고 생각되네요... 그만큼 훌륭한 작품을 만들었을테니...
  • xeraph 2008/07/09 16:22 # 답글

    프로그래밍 언어가 쉬워지면 지금까지 소홀해왔던걸 더 하게될지, 아니면 프로그래밍 언어만 배우고 끝날지 그 결과는 아무도 모르죠 ㅋㅋ 원래 잘 만든 게임이 그렇듯이.. 시작은 쉽게.. 클리어는 어렵게 (..) 하는게 좋지 않을까 막연한 생각이네요.
  • Lohengrin 2008/07/09 17:37 # 답글

    흠 저 같은 경우는 프로그래밍 언어는 도구일 뿐이라고 생각하는 편이라 용도에 따라서 골라서 사용하면 된다는 생각입니다. 숙련도의 차이가 있을 수 있겠고, 경우에 따라서는 특정 영역의 언어는 특정 사람만 쓸 수 있을 수도 있겠죠. 전반적으로 도구가 사용하기 편해 진다는 것은 좋은 일이라고 봅니다.
  • object 2008/07/10 13:39 #

    프로그래밍 언어가 쉬워지는 것은 바른 방향입니다. 그러나 그걸 제대로 다루는데는 많은 공부가 필요하죠. 자동차는 아무나 몰 수 있지만 그걸 정비하려면 자동차 좀 알아야 하듯이. 프로그래머는 단순히 자동차를 모든 직업이 아니라고 생각합니다.
  • nineye 2008/07/16 14:09 # 삭제

    프로그래밍 언어는 도구가 맞습니다. 하지만 사용하기 편해진다는 것이 프로그래머들에게 좋은 일만은 아닙니다. 사용하기 편해진다는 것은 사용하기 어려운 부분을 누군가가 사용하기 쉽게 만든 것이고, 그 부분에 대해서 뭔가 개선해야 한다면 우리는 사용하기 어렵던 부분을 알아야 할 뿐 아니라, 그것을 사용하기 쉽게 만든 사람의 사상이나 코드도 이해해야한다는 부담감이 있습니다. 물론 대충 돌아가기만 하는 프로그램을 만들 땐 알 필요가 없지만 "난 정말 뛰어난 프로그램을 개발 할 것이다.."라는 생각을 가지고 있다면 모두 이해해야 한다는 것이죠. 그리고 그런 것에 대해 이해하다보면 결국 처음으로 돌아가서 그것으로 인해 생성되는 어셈코드가 얼마나 효율적으로 돌아가는지 확인하는 단계까지 가죠... 그러면 차라리 사용하기 어려운 부분을 그대로 사용하는게 더 낫지 않을까요... 그리고 이러한 노력을 통해 전문성을 가지는 프로그래머가 되며, 그 사람이 만들어 내는 것은 그만큼의 값어치를 가지겠죠...
  • lifthrasir 2008/07/09 18:09 # 삭제 답글

    MFC/ATL의 CString은 스택 상에 들고 다니는 게 포인터 하나이고 그 포인터가 바로 문자열의 맨 처음을 가리키도록 의도적으로 구성되어 있는 걸로 알고 있습니다. (크기 데이터 등은 위치상으로 앞에 위치하는 걸로...) implicit cast가 일어나는 건 아니고 POD로 해석해서 그렇게 되어 버린다...랄까요.
  • object 2008/07/09 18:20 #

    제가 실수했습니다. 맞습니다. CString/CAtlString의 첫번째 데이터가 PXSTR m_pszData 라서 바로 그게 들어가죠. 말씀대로 printf에서 const char*로의 캐스트가 일어나는 건 당연히 아니네요. 감사합니다.
  • AnonymousY 2008/07/10 00:30 # 답글

    우와 저도 주인장님께서 과거에 하신 삽질 리스트를 100% 경험해 봤네요;;
    공감 1000% 입니다 OTL
  • object 2008/07/10 13:36 #

    다들 코딩 좋아하는 사람들은 비슷한 진화 과정을 거치죠.
  • mkk2 2008/07/10 01:07 # 삭제 답글

    한참 읽다보니 전에 기존보다 두배 빠른 png디코딩 알고리즘을 개발했다고 주장하신분 글이군요;;
    내 30분... ^^
  • object 2008/07/11 14:36 #

    과거 행적에 얽힌 글들도 읽었는데 아 정말 황당한 분이더군요. 우와 젤 황당한건 그 대단한 GUI 라이브러리에 후킹을 써서 구현했다는;; 어이쿠나.
  • 오스카 2008/07/10 11:05 # 답글

    CString 내용은 전에 회식 시간에 한 번 이야기 되었던... ㅋㅋ 결국 회식 1차 끝나고 회사 들어가서 CString 소스 코드 보고 POD로 결론.

    근데 Intel Compiler가 리눅스에서 공짜였나? 하고 찾아보니 Non-commercial app. 개발에는 공짜였군요. 흐음, 회사에 Windows 버전 하나 사달라고 할까...
  • object 2008/07/10 11:09 #

    그런데 디버깅할 땐 소스 코드 매칭이 좀 문제가 있어보이네요..
  • 코에이 2008/07/11 20:14 # 삭제 답글

    사족입니디만, Intel Compiler 말고도 gcc도 -Wall 주면 std::string를 printf를 쓸때 warning을 내주긴 합니다. :) 인텔컴파일러가 gcc 기반으로 최적화를 했다는 루머를 들은거 같기도 해서요 ^^:
  • object 2008/07/12 02:07 #

    컴파일러 워닝이야 서로 서로 영향을 주고 받을 수 있겠죠. 그런데 최적화 기술만 놓고보면 gcc는 좀 아래입니다. SSA도 4.0에 되서야 들어왔고 벡터라이저도 아직 없고 gcc가 그렇게 뛰어난 컴파일러가 아닙니다.
  • nineye 2008/07/16 14:18 # 삭제 답글

    전 개인적으로 M$사를 싫어해서 그런지는 몰라도 MFC기반으로 생성되는 소스가 지저분하다고 생각하며, boost나 stl과 같이 template을 이용한 코드가 정말 예쁘다고 생각합니다... 그러한 library들 내에는 성능을 위해 이해하기 어렵고 지저분한 코드를 사용한 부분도 있지만 전체적인 구조나 코딩 스타일을 보면 맘에 듭니다. 물론 코딩 스타일은 주관적인 면이 강해서 자신이 깔끔하다고 생각하는 스타일이 대부분 다르고, 아주 이상하지 않다면 이에 대해 좋지 않다고 말 할 수도 없습니다. 저는 변수나 함수명이 긴 것을 싫어하기 때문에 요즘 비난 받고 있는 헝가리안 스타일을 쓰기도 하니까요...
  • object 2008/07/16 22:25 #

    사실 MFC가 프로젝트에 깊숙히 관여할 수도 있지만 저는 일반적으로 엔진부분과 GUI를 분리하기 때문에 MFC 같은 툴킷의 영향을 최소화 합니다. 그래서 뭐 MFC를 써도 그렇게 지저분해지지는 않았습니다. 별 생각없이 다 MFC AppWizard가 생성해주는 코드에 넣으면 정신이 없어지겠죠?

    MFC가 객체지향도도 상당히 낮고 불완전한 모습도 많지만 어쨌든 매우 성공한 라이브러리임에는 틀림 없습니다. 정작 MS 내부에서는 MFC는 쓰지 않지만.
  • f 2008/08/04 00:47 # 삭제

    변수나 함수명이 긴것을 싫어하시면서, stl 이나 boost 같은 코드를 예쁘다고 생각하는건 모순 아닌가요.
  • 2008/08/13 03:23 # 삭제 답글

    이 논쟁은 약 12년 전에도 있었던 논쟁이군요. 대신 그 시절엔 모든 자료구조 자체를 STL 처럼 통일된 인터페이스를 가진 템플릿으로 만드냐, 아니면 자료구조에 대한 동작만을 템플릿으로 만드냐, 아니면 템플릿화 대신 상속과 void* 만으로 해야 하냐의 논쟁이었지요.

    물론 그 당시에도 답은 나오지 않았답니다. 답이 나오지 않은 이유는 개발분야마다 요구사항이 틀리기 때문이었답니다.

    그 당시 그리고 그 이후로 개발경험을 쌓으면서 개인적으론, STL은 어디까지나 실행시간이 짧고 생명주기가 짧은 소프트웨어를 낮은 비용으로 빠르게 개발할 경우에나 맞지, 긴 실행시간과 생명주기를 가진 소프트웨어 개발엔 적합하지 않다는 결론을 내렸답니다.

    무엇보다 STL같은걸 사용하도록 교육할 경우, 개발자가 pool에 대한 연동을 못하고 개별 객체의 생성을 너무 힙에 의존하는 성향을 보이며, 병렬처리 상황에서 임계영역을 줄이지 못하는 모습을 보이는 원인이 컸답니다.

    이런 개발자는 서버 개발에는 좀 부적합하죠.
    차라리 그렇게 개발하려면 PHP나 JSP, ASP 혹은 자바 서블릿으로 가는게 낫다고 봅니다..

    자료 구조 자체는 매번 비슷한 것 같지만, 병렬처리 상황에선 임계영역을 제거하거나 최소화하기 위해 변형을 요구하며, 또한 최적화된 인덱싱을 위해 단일데이터구조를 쓰는 경우가 거의 없고 보통 2-3개의 자료구조가 혼합된 형태를 사용하거든요.

    뭐든지 만병통치약이란 없답니다. 헌데 요즘 STL 이 한 때 솥뚜껑에 들어간다던 JAVA 처럼 너무 만병통치약처럼 사용되는 문제가 있는게 아닐까 하는군요.
  • 2008/08/13 03:37 # 삭제 답글

    개인적으론.. 개발환경이나 목적을 배제하고 STL 만 가지고 이걸 써야 하나 말아야 하나로 논쟁하는건...

    디씨에서 하는 말로 병림픽이라고 봅니다. 병신들의 올림픽... 병림픽엔 승자가 없다고 하죠.
  • object 2008/08/13 08:09 #

    옳으신 말씀입니다. 저도 지금 프로토타이핑할 때만 STL쓰고 최종 코드는 specialized된 자료구조로 씁니다.
  • Vany 2008/12/11 15:13 # 삭제 답글

    한RSS 타고 어제 처음 이 블로그를 방문해서, 유익한 글들 잘 읽고 있습니다.

    링크다신 쓰레드 때문에 한 두 시간 정도 말려버렸네요.
    덕분에 크게 몇 번 웃고 갑니다.

    감사합니다.
댓글 입력 영역