오늘 aTCenter에서 TR1에 대한 MSDN세미나를 마치고 돌아왔습니다.

오늘 너무너무 많은 실수의 연발이었기에 오자마자 세미나 후기를 쓰고 있네요 T.T
무대 공포증이 있는지...  머리속이 하얗게 되어 거의 주화입마에 빠져 버렸네요 ㅋㅋ..
어찌 되었던 찾아와 주신 모든 분들께 정말 감사드립니다.
컴파일하느라 시간을 다 보내 버려서 미쳐 하지 못했던 몇가지에 대해서만 다시 언급을 하려 합니다.  또한 세미나 자료를 첨부하여 놓겠습니다.





우선 중요한 shared_ptr과 weak_ptr을 충분히 설명을 하지 못한듯 하네요
swap을 설명하다가 얼버무려졌는데요..  만약 shared_ptr에서 swap을 제공하지 않는다면 아래와 같이 swap을 할수 있겠죠

#include <iostream>
#include <memory>
#include <string>
using std::tr1::shared_ptr;
using std::string;
int main()
{
    shared_ptr<string> a(new string("meow"));
    shared_ptr<string> b(new string("purr"));

    //swapping it
    {
        shared_ptr<string> t(a);

        a = b;
        b = t;
    }
    return 0;
}

이렇게 되면 많은 반복 copy및 생성이 이루어 집니다.  이걸 해소 하기 위해서 swap을 제공 합니다.
바로 아래와 같이 쓸수 있겠죠..

a.swap(b); // a <-> b swap됩니다.
swap(a, b); // a <-> b swap됩니다.

이때는 copy및 temporary를 생성하지 않고 a와 b가 가르키는 pointer만을 교체 함으로써 빠르고 간결하게 swap이 이루어질수 있도록 합니다.

또한 shared_ptr은 "new"와 "delete"의 pair로 이루어져 있다고 말씀 드렸는데요..  만약에 "delete"대신 "free"를 할필요가 있다면 어찌해야 할까요?  그런 경우를 위해서 shared_ptr은 deletor를 전달할 수 있도록 하고 있습니다.

struct deletor {
    void operator() (int *p )
    {
        delete p;
        cout << "deletor" << endl;
    }
};

int main()
{
    shared_ptr<int> a(new int(10), deletor() );  // 함수 객체 전달
}

위와 같이 생성자 또는 reset함수를 이용해서 함수객체를 전달 받고 있습니다.  deletor 함수객체에서 "delete" 대신 "free"를 할수도 있겠죠.

다음은 weak_ptr에 대한 내용입니다.  weak_ptr은 간단히 reference_count를 올리지 않는 shared_ptr이라고 할수 있습니다.  이것이 왜 필요하느냐?  reference_count를 갖는 shared_ptr이 서로를 point하게 될경우 순환참조가 일어나서 둘다 해제되지 못하는 상황에 빠질수 있습니다.  다음의 예제를 봐주세요.

struct S {
    S(T n) { cout << "construct" << endl; }
    ~S() { count << "destruct" << endl; }

    shared_ptr<S> next;
};

int main()
{
    S *head = new S;
    S *node = new S;

    shared_ptr<S> root(head);
    head->next = shared_ptr<S>(node);
    node->next = root;  // cycle
    return 0;
}
위와 같은 코드가 있을수 있죠.( ^^)  root는 node의 next 라는 shared_ptr이 다시 가르키게 되어 순환참조가 일어납니다.  코드를 수행하면 "construct" 만 두번 발생하는 것을 보실수 있습니다.  이때 weak_ptr을 사용하게 됩니다.

struct S {
   S(T n) { cout << "construct" << endl; }
   ~S() { count << "destruct" << endl; }

   weak_ptr<S> next;
};

int main()
{
   S *head = new S;
   S *node = new S;

   shared_ptr<S> root(head);
   head->next = shared_ptr<S>(node);
   node->next = root;  // no cycle
   return 0;
}
 node->next는 여전히 root를 가르키지만 node->next는 weak_ptr이기에 reference를 올리지 않습니다.  해서 shared_ptr이 정상적으로 destruct될수 있습니다.  코드를 수행하면 "construct", "destruct"가 두번씩 프린트 되는걸 보실수 있습니다.

shared_ptr은 정말 잘 만들어져서 대부분에 케이스에서는 문제가 없습니다만  몇가지 실수 할수 있는 예를 보죠 개발자가 억지로 만들어 낸다면 컴파일러는 어쩔수 없습니다. ^^

int* p = new int(100); // raw pointer생성
shared_ptr<int> sp(p); // raw pointer를 shared_ptr를 initialize
shared_ptr<int> sp2(p); // raw pointer를 다시 shared_ptr로 initiaize
이렇게 되면 double deletion이 일어나게 됩니다.  당연하죠 shared_ptr은 raw pointer "p"를 다른 shared_ptr이 또 pointing하고 있을거라는것은 꿈에도 모를테니까요..  주의를 하시는 수밖에 없습니다.
또하나는,

shared_ptr<int> sp = new int(100);
이런 코드 입니다.  언듯 보면 될듯 싶습니다만,  안됩니다.  shared_ptr의 "operator=" 이 받아들이는 타입에 pointer는 없습니다.  같은 shared_ptr또는 STL의 auto_ptr을 받아들입니다.  RAII 에 입각해서 initialization을 해서 사용하는것을 원칙으로 하고 있습니다.

마지막으로, 아래코드를 보시죠.

somefunc(shared_ptr<T> (new T), otherfunc() );
위와 같은 함수가 있습니다.  somefunc는 shared_ptr을 인자로 받고 또한 다른 인자를 하나더 받네요.  이경우에 leak이 발생할수 있습니다.  근데 머가 문제일까요?

컴파일러는 위 함수를 해석하는데 기준이 모호함에 원인이 있습니다.  컴파일러가 만약 아래와 같이 해석한다면
1. new T 수행
2. otherfunc() 수행
3. shared_ptr() 생성자 수행

위와 같은 경우 otherfunc()가 excepting을 발생 시켰다면 new T는 dangling pointer가 되고 shared_ptr()생성자는 수행되지 못합니다.
shared_ptr의 유용함을 강조 하고 싶었는데,  개인적으로 많이 아쉬운 오늘 하루 입니다.

한가지 더 제가 놓친 부분은 bind를 설명하면 함수 객체에 대해서 언급이 없었네요..  머 이미 잘 아시는 분들도 계시겠지만,  조금 부연 설명을 하면 함수객체는 "객체를 함수 처럼"이용 가능하게 하는겁니다.  다음의 코드를 봐 주세요

class stat {
    int count;
    int sum;
public:
    stat() : count(0), sum(0), average(0) { }
    // operator () 재정의 <- 함수 객체로써 구현
    int operator() (int i)  {
       sum += i;
       count++;
       return sum;
    }
    int GetCount() { return count; }
    int GetSum() {return sum;}
    double GetAverage() {
          return static_cast<double>(sum)/count;
     }
}
"stat" 이란 클래스를 함수 객체로 정의 하였습니다.  보통 클래스와 같지만 operator()를 overload했다는 점이 틀린점이죠..  이로써 함수객체로 사용할 수 있습니다.  다음의 사용예를 봐주세요..

int main()
{
    stat S;
    for( int i = 0; i <= 100; i++ )
    {
       S(i); // 함수 객체 호출
    }
    cout << "sum = " << S.GetSum() << endl;
    cout << "avg = "  << S.GetAverage() << endl;
}
위와 같은 함수 객체를 함수처럼 함수를 넘길수 있는 bind같은 template를 이용하여 일반화 프로그램밍을 할수 있습니다. 

여전히 설명이 부족한것 같지만 앞으로 블로그를 지속적으로 업데이트 하며 오늘을 잘못을 지워보도록 노력해 봐야죠 T.T

오늘 와주신 분들께 참으로 고맙고 죄송합니다. ^___^;;;






Posted by 제로원
Bjarne Stroustrup 교수가 C++0x를 소개하는 동영상입니다.  57세의 C++ 창시자가 소개하는 C++의 미래에 대해서 Texas A&M 대학교에서 실제 강의 하는 내용을 1시간 30분 정도로 보여주고 있습니다.

동영상 보러가기

동영상은 페이지 하단에 다운로드 가능하도록 되어있습니다.

C++창시자로 부터 듣는 C++이야기는 정말 매력적인데요 ^_^
(약간 살찐 브루스윌리스 닮지 않았나요? ^__^;;)
Posted by 제로원
TAG c++, TR1, 정보
MFC 세미나 자료를 올립니다.  참가해 주신 많은 분들께 감사드립니다. 
어리버리 세미나가 되어 송구 스럽습니다.  다음기회가 있다면 더 좋은 시간이 될수 있도록 노력하겠습니다.

[PPT & Demo Sample]


[Diagram]
사용자 삽입 이미지사용자 삽입 이미지사용자 삽입 이미지

Posted by 제로원