오늘의 삽질: boost::shared_ptr<T> 이렇게 쓰면 망한다!
강력하고 C++ 패러다임에 잘 부합하기로 유명한 라이브러리로 Boost의 일련의 라이브러리들이 있다. 그 중에서도 유명한 것을 꼽으라면 STL의 generic programming 패러다임 중 특히 함수 객체(함수자; function object; functor)를 잘 활용하게 해주는 boost::lambda 라거나, 정규식 팩키지로 사용되는 boost::regex, 그리고 이 포스팅의 주인공인 boost::shared_ptr 를 포함한 스마트 포인터 팩키지가 있다. 물론 이외에도 C++ TR1 에 포함된 많은 라이브러리들이 있으니 직접 https://boost.org 를 방문해 볼 것을 권한다 :) Boost의 메모리 관련 라이브러리 중에서도 포인터의 참조 카운트에 기반해서 동작하는 스마트 포인터인 shared_ptr&lt;T&gt;는 그 편리함과 거의 포인터에 유사한 동작을 제공하며, 별도의 라이브러리를 빌드할 필요도 없고 단순히 헤더파일만 추가해주면 되서 쓰기가 편하다.
Peanuts
흔히 찰리 브라운Charlie Brown과 스누피Snoopy 로 말하면 많은 사람들이 알아듣는 찰스 M. 슐츠(Charles M. Schulz)의 Peanuts는 사실 rein이 가장 좋아하는 코믹 스트립이다. 어제 뜬금없이 이게 다시 보고싶어져서 국내에 발행된 것(신영 미디어를 통해 발간된게 있다)을 찾아봤으나 역시나 품절. 그래서 아마존을 찾아보니 멋진 물건이 있다. 조금 더 뒤져보니 2004년부터 2016년까지 순차적으로 Peanuts 스트립을 묶어서 양장본으로 발간하고 이 것들을 2권씩 묶어서 매년 10월에 박스셋으로 내놓는다고 한다. 현재 8개의 볼륨 = 4개의 박스셋이 나와있는 상태.
intel Threading Building Block
멀티스레드 프로그래밍을 할 때마다 느끼는거지만, 실제로 겪게 되는 작업 중 상당수가 굉장히 저수준low-level의 무언가라고 느낄 때가 많다. 특히 일일이 락lock을 잡고 락 순서 문제를 해결하고, 각각의 동기화된 작업들을 연동도 시켜줘야하고, 특정 컨테이너들이 동시 접근할 때 어떻게 처리되어야 할지도 일일이 결정해줘야 한다. 이런 방식의 문제는 이렇게 일일이 안해주면 성능이 안나오는 경우가 있다 라는 것인데, 저수준 작업을 최대한 줄이고, C++ 패러다임에 맞는 형태로 프로그래밍하려는 노력으로 intel에서 제공하는 intel Threading Building Block (이하 intel TBB ) 이라는 라이브러리가 있다.
사용중인 Live Writer 플러그인 버그
대략 한 달 넘게 Live Writer로 글을 쓰다보니, 워드프레스에 있는 코드 입력 플러그인을 쓰지 않게 되었다. 그래서 Live Writer 용 플러그인을 좀 찾아봤는데, C++까지 지원되는 Syntax Highlighter라는 걸 발견했다. 그러나 링크를 하지 않는 이유가 있다(…). ASCII 범위를 벗어나는 문자를 입력하면 캡쳐된 화면처럼 깨진 문자가 표시되고, 입력을 계속하고 있으면 각 키 입력마다 깨진 문자가 2배씩 늘어난다.
Python string.find()의 성능
바로 직전에 C++ STL의 std::string.find()의 성능을 테스트했다. 그리고 실망했다. 이번에는 요즘 널리 사용되고 있는 스크립트 언어 중 하나인 Python의 문자열을 가지고 테스트를 진행해봤다. 이전 테스트와 동등한 머신에서 WindowsXP/Python2.5을 사용하여 테스트를 수행하였다. Python의 문자열 검색이 일정 길이 이상에선 STL의 문자열 검색보다 월등히 빨랐다. 테스트 범위의 문자열에서 100ms초 이하에 검색이 끝나는 결과를 보여줬다 – 짧은 길이에서는 너무 빨리 결과가 나와서 100번 정도 루프를 돌리고 시간을 측정해야 했다. 그리고 가장 중요한 것, 문자열 길이를 늘려가는 것에 대해(이전 테스트처럼 원본 문자열과 패턴 문자열을 모두 증가) 선형으로 복잡도가 증가했다.
std::string.find() 의 성능
얼마 전에 jstrane군이 std::string.find()가 느리다고 불평하면서 linux/g++로 성능을 테스트해서 포스팅한 것이 있다. Win32/VC++ 환경에서도 테스트를 진행해봤다. 여기의 그래프가 WindowsXP/VC++2005를 가지고 테스트한 결과다. (테스트 설계는 jstrane 블로그를 참조하자; naive 입력에 대해서 최악의 성능을 뽑아내는 방식이다) 길이에 대한 std::string.find()의 실행 시간 그래프가 2차 곡선을 그리고 있다. 즉, 원본 문자열의 길이가 m, 찾으려는 패턴의 길이가 n일 때 O(mn) 의 시간 복잡도를 갖는다. jstrane이 테스트한 경우에도 그랬지만 STL의 string.find() 함수 구현이 _naive한 형태_이기 때문에 생기는 문제다.
Live Writer manifest 파일을 보면서
Windows Live Writer는 블로그 설정을 자동으로 읽어오는 기능이 있다. 단 해당 블로깅 툴에서 특정 파일(wlwmanifest.xml)을 제공해줘야한다. 이 블로그의 경우엔 이런 xml 파일로 제공되고 있다. 이 파일을 잘 사용하면 블로그 개발자와 Live Writer 쪽 개발자의 일이 잘 쪼개지게되고, 사용자의 부담도 줄어들 수 있는 것 같다. 그래서 포스팅을 하나. 이 파일이 Live Writer 쪽에서 사용되기 시작한 것은 베타 2 부터인데 (현재 베타 3) manifest 파일에 관한 MSDN의 설명에 따르면, 블로깅 툴에서 사용 가능한 기능들의 목록을 알려줄 수 있다.
C++에는 final 키워드가 있는가?
Java 프로그래밍 언어를 처음 접한게 아마 학부 1학년 2학기의 컴퓨터 프로그래밍 수업이었던 것 같다. 당시 Java의 기능 중에 마음에 들었던 것이 final 키워드의 존재였다. Java의 final 키워드는 해당 함수를 static 하게 바인딩(binding)하게 해주거나, 상속받지 못하게 하거나 등등의 역할을 하는데, 주목했던 부분은 바로 상속을 금지하는 것. C++의 특성상, 특정 class를 상속받지 못하게하는게 필요할 때가 있다. 예를 들어서 virtual function table (가상 함수 테이블; 일명 vtable) 포인터를 위한 포인터 공간이 아까워서(매우 작은 데이터 클래스가 필요한 경우) 이러는 경우도 있고, 라이브러리의 요구사항에 의해서 그런 경우도 있을 수 있다.
밴티지 마스터 택틱스의 추억
고어핀드군의 파랜드 택틱스(FT) 포스팅을 보고 삘받아서 나도 밴티지 마스터 택틱스(VMT)에 관한 포스팅을 하나. Falcom에서 제작했으며 시기를 1998년에 발매되어 한동안 즐겼었던 게임이다. 일본식 RPG의 명가 Falcom에서 제작되어서인지 SRPG에 속한다고 주장하고 있으나 실상은 일종의 턴방식 전략 시뮬레이션 게임. 게임 자체는 구조가 굉장히 단순하다. 우선 자기 자신의 아바타인 &ldquo;마스터&quot;가 있으며, 이 마스터는 네이티얼이라는 소환수를 소환하여 전투를 벌이게 된다. 4 속성의 소환수와 그 안에서의 상성관계, 그리고 각 계열의 다양한 소환수를 사용할 수 있다. 자원은 딱 하나 마나인데, 이 마나는 점령한 마법석 수에 마스터의 마법 능력에 관한 상수를 곱해서 일정 턴마다 들어오게 된다.
C++의 연산자는 내장 연산자가 아닐 수 있다
C++ 의 연산자들은 overloading 될 수 있고, 이에 따라 동작이 변할 수 있다. 내가 몇 일전에 KLDP 질문 글에 답변을 올리다가 저지른 실수를 적어보겠다. 사실 질문글 자체는 간단했는데, C-style 문자열을 위한 메모리를 동적으로 할당하는데 strlen 으로 bytes 길이를 구한게 아니라 sizeof(char* type pointer)로 포인터의 크기를 구한 후에 문자열을 복사해서 런타임 오류가 발생하는 문제였다. 그래서 &ldquo;strlen( )&rdquo; 쓰세요로 답변 끝. 문제는 여기에서 시작. 다른 한 명이 &ldquo;delete로 char* 배열을 제거할 때와, delete[] 로 배열을 제거할 때 차이가 나지 않았다&rdquo; 라고 추가 질문을 해서, &ldquo;내장 타입에선 차이가 없다&rdquo; 라고 답변을 달았다.