Media Log

마이크로소프트에서 카사블랑카라고 이름지어진 흥미로운 라이브러리를 발표했다.


http_client bing( L”http://www.bing.com/search” );
bing.request( methods::GET, L”?q=S.Somasegar” )
.then( []( http_response response ) {
cout << “HTML SOURCE:” << endl << response.to_string() << endl; })
.wait();


listener::create( argv[1], []( http_request req ) {
req.reply( status_codes::OK, “Namaste!” ); })
.listen( []{ fgetc( stdin ); } )
.wait();


여기 공식 페이지에 간략하게 소개가 있으며, 허브 셔터가 자신의 블로그에 따로 소개해주기도 하였다.

아마 Restful api를 제공하는 서비스들의 클라이언트 코드로써 가장 많이 사용되지 않을까 싶다.

 

얼마전 있었던 마이크로소프트의 Going Native 2012 행사에서 허브 셔터가 말하길,

C++ 언어는 다른 최신 언어들에 비해 부족한 점이 거의 없다. 부족한 것은 바로 라이브러리이다. 라는 말을 했었는데 아주 인상 깊게 들었다. 프리젠테이션 자료를 너무 인상적으로 만들어서 더욱 설득 당했는지도 모르겠다.

아래 주소에서 그 동영상을 볼 수 있다. 1시간 17분 쯤부터 보기 시작하면 된다.

http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/C-11-VC-11-and-Beyond


어쨌거나 좋은 C++ 라이브러리들이 빨리 빨리 구현되기를 바란다. 그래야 Going Native Again 할 것 아닌가.



 

C++에서 함수 이름이 맹글링 되는 것은 다들 알고 있는 사실일 것이다.
링커 오류를 만나게 되면 원인을 분석하기 위해 때때로 함수의 오리지날 이름이 알고 싶을 때가 있다. 마이크로소프트의 도구로 만들어진 함수들에 대해서는 undname 이라는 프로그램이 바로 그런 일을 해준다.

레이몬드 첸의 한 포스트를 읽다가 그는 단순한 함수들에 대해서는 undname을 사용하지 않고도 한눈에 척 알아볼 수 있는 것 같다는 느낌을 받았다.
어떻게 그런 일을 할 수 있는지 알아보다가 강성훈씨가 쓴 이 포스트를 보게 되었다. 그가 말하는 것처럼 아마 현재까지 가장 잘 정리된 자료라는데 동의한다. 어린 나이에 정말 대-_-단 하다고 밖에는 말할 수 없다.

...하지만 나는 한참 살펴보다가 결심했다.
'빌어먹을. 나는 그냥 undname이나 써야겠다.'

흐아, 생각처럼 간단한 일이 아니었다.
그런데 레이몬드 첸은 정말 간단한 함수 정도는 추측할 수 있는 것일까? 아직도 잘 모르겠다.


나는 이 책의 0x 버전을 읽었는데, 얼마전에 정식판이라고 할 수 있는 C++11 버전이 발표되었다.
거의 모든 장이 아래 그림 처럼 코드 조각들로 이루어져 있고 스캇마이어스의 짧은 설명들로 보충된다.
예제 코드들이 궁금했던 점들을 너무도 잘 긁어주기 때문에 C++11의 새로운 기능들을 빠르게 익히는데 도움이 많이 되며 영어 때문에 부담스러워하지 않아도 된다.


이펙티브 C++ - 10점
스콧 마이어스 지음, 곽용재 옮김/피어슨에듀케이션코리아

한 동안 계속 C로만 코드를 짜다가 최근 회사를 옮기면서 C++를 다시 하고 있는데 C++로 코딩하는게 그렇게 재미있을 수가 없다.

이 책은 2006년도에 회사에 갓 들어가서 한 번 읽었던 책인데, 최근 읽은 Effective STL이 너무 재미 있어서 5년여 만에 다시 꺼내어 읽어 본 책이다.
두번째로 읽었지만 그 당시 읽었던 것보다 더 재미있게 읽었고 정말 많은 부분을 놓치고 지나갔었다는 것을 알게 되었다.

이 세상에 스캇 마이어스처럼 C++를 재밌고 간결하게 설명할 수 있는 사람이 있을까? 있을수도 있지만 아마 비야네 스트롭은 아닐 것이다. 비야네의 책은 좋은 책임에는 분명하지만 정말 재미없고 어렵다. -.-

책을 읽다가 문득 궁금했다. 혹시 이제 C++11 버전 에디션을 하나 내지는 않을까? 어쩌면 이미 준비하고 있는 것은 아닐까?
그래서 한 번 메일을 보내서 물어봤는데, 맙소사 스캇 마이어스가 내게 답장을 해주다니.

안타깝게도 아직은 계획에 없다고 한다. 새 버전의 책은 분명히 쓸만한 가치가 있지만 C++11을 Effective하게 사용하는 법을 쓰기 위해서는 먼저 그에 대한 충분한 경험이 필요하기 때문이라고 한다.
뭔가 새 버전만 나오면 남에게 뒤질세라 대충 공부해서는 얼른 책 한권을 만들어 내는 요즘 세상에 참 멋진 해커가 아닌가?
아마도 스캇 마이어스가 말하는 충분한 경험이란 꼴랑 두세달 공부하는 것은 아닐 것이다.
오래 기다려야 할 것 같아서 안타깝긴 하지만 언젠가는 꼭 다음 에디션이 나오게 되지 않을까 싶다.

_countof 매크로

2011. 3. 15. 06:48 | Programming

'Programming' 카테고리의 다른 글

윈도우 드라이버를 만들 때 알아야 할 기초적인 내용들  (2) 2011.05.23
Duff's Device  (0) 2011.04.07
FIELD_OFFSET 매크로  (1) 2011.03.01
PAGED_CODE 매크로  (6) 2011.02.27
디렉터리의 읽기 전용 속성  (4) 2011.02.20
게임 개발자를 위한 C++ - 8점
서진택 지음/민프레스(민커뮤니케이션)

대학교 2학년 2학기 때, C언어에 어느 정도 익숙해지고 C++을 혼자서 조금씩 공부해 가던 때에, 친구의 추천으로 이 책을 읽었다.

당시 C++을 잘 모르던 내게 이 책은 너무나 버겨웠는데, 그럼에도 불구하고 이 정도 고급 주제를 다룬 국내 서적은 찾아 보기 힘들었기 때문에, 이해 될 때까지 연구실 책상에서 보고 또 보고 했던 기억이 난다.

그렇게 여러번 보다 보니 처음에는 전혀 모르겠던 내용들도 어렴풋이 이해하게 되고 나는 C++에 조금씩 익숙해져 갔다.

이 책은 내용은 괜찮았지만, 편집이 엉터리였다. 인쇄가 아마 -> 연산자가 모두 공백으로 나왔었언가? 그런 류의 심각한 결함이 있었다.

하지만 이 책에서 C++의 여러 문법들과, 오버로딩 오버라이딩, 상속 관계에서의 생성자와 소멸자의 호출 순서, 복사 생성자, this 포인터, 가상함수와 가상함수 테이블, 연산자 오버로딩등을 배울 수 있었다.

지금도 기억에 강하게 남아있는 부분은 복사 생성자인데, 이 책의 저자는 복사생성자를 참 중요하게 강조했던 것 같다.

복사 생성자란, 말 그대로 객체가 복사 될 때 호출되는 생성자이다.
CString s1(_T("string"));
CString s2( s1 ); // 또는 CString s2 = s1;


두번째 줄에서 s1을 s2에 복사하면서 복사 생성자가 호출 된다.
그냥 생성자가 아니라 CString::CString( const CString& ) 의 시그내쳐를 가진 복사 생성자 말이다.

하지만 코드를 이렇게 작성한다면,
CString s1(_T("string"));
CString s2;
s2 = s1;


위와 같은 경우에는 s2를 기본 생성자를 통해 객체를 생성한 뒤 operator=() 을 통해서 s1을 s2에 복사한다. 그러므로 위 코드에서는 복사 생성자가 호출 되지 않는다.

간단한 내용이지만, 생성자에서 멤버를 new하고 소멸자에서 그 멤버를 delete하는 경우에 복사 생성자를 정의해주지 않으면 복사 될 때 프로그램은 죽는다.
복사 생성자를 정의하지 않았을 때 컴파일러가 알아서 복사 생성자를 만들어 주지만 멤버에 포인터가 있다면 그 포인터 값을 그대로 복사하도록 코드를 생성한다.

이런 식으로 말이다.
class A
{
public:
    //somemethod();
private:
    int* pPointer;
};

A::A( const A& copy )
{
    this->pPointer = copy.pPointer;
}// 컴파일러는 이런식으로 복사생성자 코드를 만들어준다.


근데 A 클래스 생성자와 소멸자가 다음과 같았다고 하면,
A::A()
{
    this->pPointer = new int();
}

A::~A()
{
    delete this->pPointer;
}


이 클래스를 이런식으로 사용할 때,
{
    A obj1;
    A obj2 = obj1;
}


블락이 끝날 때에 프로그램은 죽는다.
- 사실 죽는다는 표현 보다는 정의되지 않은 동작을 수행한다. 라고 하는 것이 좀 더 정확하다. 하지만 일반적으로 거의 모든 경우에 뒤진다. :)

왜냐하면 obj1을 생성 할 때 불리는 기본 생성자에서 멤버 변수에 메모리를 동적 할당했고,
obj1을 obj2에 복사하면서는 복사생성자를 통해 obj2를 생성했는데, 이때는 pPointer에 새로운 메모리를 할당한 것이 아니라 obj1의 멤버 변수 pPointer의 주소만을 복사했기 때문이다.
블락이 끝나면서 소멸자가 호출 될 때는 각 객체의 소멸자가 모두 호출 되면서 pPointer를 해제하려고 한다.
하지만 2번째 delete할 때 이미 해제한 포인터를 다시 delete하려고 하므로 오류.

이럴 때는 복사 생성자를 컴파일러에 맡기지 말고 다음처럼 직접 작성해주어야 한다.
A::A( const A& copy )
{
    this->pPointer = new int( *copy.pPointer );
}


복사 될 때도 메모리를 동적으로 할당하고 복사본의 값을 가져오면서 deep copy가 되었다.

복사 생성자가 언제 호출되는지 아는 것도 중요하다.
첫번째 경우는 위 코드에서 설명했고,
두번째 경우는 함수 파라메터로 넘길 때이다.
void SomeMethod( A obj );

이런 함수가 있다면,
A obj;
SomeMethod( obj );

이렇게 호출 할때에 객체가 복사되면서 복사 생성자가 호출된다.

만일 함수가 void SomeMethod( A& obj ) 이렇게 참조를 받도록 정의되어 있다면, 이런 함수들은 물론 호출 할때 객체가 복사되지 않으므로 복사생성자도 호출되지 않는다.

마지막은 객체를 리턴할 때이다.
{
    A obj;
    // some codes...
    return obj;
}


이 때 역시 객체를 복사하므로 복사생성자가 호출 된다.

물론 C#이나 자바 등의 언어에서는 참조자만 사용되고 garbage collector 가 자원 해제 몫을 처리해 주기 때문에 이런 종류의 고민은 하지 않아도 된다.