SlideShare ist ein Scribd-Unternehmen logo
1 von 54
BoostBoost 라이브러리의 내부 구조라이브러리의 내부 구조
에 사용된 기법을 응용하기에 사용된 기법을 응용하기
KOG, 서진택
jintaeks@gmail.com
2015 년 11 월 11 일
발표자 , jintaeks@gmail.com
 2000 년 ㈜ Kog 입사
– 프로그래머로 게임 개발 시작
 ~2015 년 9 월 ㈜ Kog 프로그래머
– 프로그래머로 게임 개발 및 기술 지원 프로그래밍
– 참여 게임
• 와일드랠리
• 범퍼킹재퍼
• 엘소드
• 얼티밋레이스
 저서
– 게임개발자를 위한 C++, 민프레스 , 2003
– MFC 의 구조와 원리 , 한빛미디어 , 2005
2
발표순서
 base-from-member idiom
 BOOST_FOREACH 의 내부 구조
– if-for combination idiom
– RAII idiom
– int-to-type idiom
– BOOST_TYPEOF
 boost::shared_ptr 의 내부 구조
– copy-and-swap idiom
– safe-bool idiom
 Q&A
3
 이 발표는 boost 라이브러리에서 가장 많이
사용하는 BOOST_FOREACH() 와
shared_ptr 의 내부 구조를 분석합니다 .
 그리고 바닥부터 해당 기능을 구현합니다 .
 이 과정을 통해서 boost 가 사용한 기법들
을 프로그래밍에 응용하는 방법을 제시합
니다 .
base-from-member: 문제 상황
class KObject
{
public:
KObject()
{
m_iInitialized = 99;
}
int GetInitialized() const
{
return m_iInitialized;
}
private:
int m_iInitialized;
};//KObject
4
class KBase
{
public:
KBase( KObject& obj_ )
{
std::cout << obj_.GetInitialized() << std::endl;
}
};//class KBase
 상속받은 클래스의 멤버를 베이스 클래스
가 접근하는 경우가 있습니다 .
 KBase 의 생성자에서 m_object 의 멤버를
호출하는 것은 객체가 아직 초기화되지 않
았으므로 안전하지 않습니다 .
base-from-member: 해결방법
struct KPrivateBase
{
KObject m_object;
};//struct KPrivateBase
class KDerived2 : protected KPrivateBase, public KBase
{
public:
KDerived2() : KBase( m_object )
{
}
private:
//KObject m_object;
};//class KDerived
5
 base-from-member idiom 은 문제를 해결하
기 위해 다중 상속에서 호출되는 클래스 생
성자의 순서를 이용합니다 .
 boost 의 많은 곳에서는 , 베이스 클래스의
생성자에서 완전히 초기화된 객체를 접근
하기 위해 이 방법을 사용합니다 .
BOOST_FOREACH 구현에 필요한 idiom
6
문제제기 : BOOST_FOREACH
std::vector<int> vecInt;
BOOST_FOREACH( int& a, vecInt )
{
}
7
 어떻게 매크로에 사용한 변수의 범위를 { 와 }
로 제한하는 것이 가능할까요 ?
관찰 : if 의 조건문에 사용한 변수
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <boost/foreach.hpp>
#include <boost/typeof/typeof.hpp>
void main()
{
if( int iBlockScope = 0 ) {}
else
{
iBlockScope = 3;
std::cout << iBlockScope << std::endl;
}
//std::cout << iBlockScope << std::endl; // invalid access
}//main()
8
 if 문에 선언된 변수는 if 블록의 하부에서 사용
할 수 있습니다 . 또한 if 블록을 빠져 나가면 접
근할 수 없습니다 .
 즉 if 문에 선언된 변수의 범위 scope 는 if- 블록
안으로 제한됩니다 .
 변수를 true 가 아닌 값으로 초기화하면 , else-
블록에서 접근하는 것이 가능합니다 .
관찰 : for 에 사용한 문장
#include <iostream>
void main()
{
if( int iBlockScope = 0 ) {}
else
for( printf( "hello worldrn" ); iBlockScope == 0; iBlockScope = 1 )
{
iBlockScope = 3;
std::cout << iBlockScope << std::endl;
}
/**
hello world
3
계속하려면 아무 키나 누르십시오 . . .
*/
}//main()
9
 for 문의 첫번째 문장에는 조건에 상관없이
자유롭게 문장 statement 을 적을 수 있습
니다 . 또한 for 문에서 선언된 변수는
block scope 를 가집니다 .
관찰 : { 와 } 사용이 가능한 RAII 매크로 정의
#include <iostream>
#define RAII( statement_ ) 
if( int iBlockScope = 0 ) {} 
else 
for( statement_; iBlockScope == 0; iBlockScope = 1 )
void main()
{
RAII( printf( "hello worldrn" ) )
{
iBlockScope = 3;
std::cout << iBlockScope << std::endl;
}//RAII()
/**
hello world
3
계속하려면 아무 키나 누르십시오 . . .
*/
}//main() 10
 RAII 는 초기화 initialize 코드와 마무리
finalize 코드가 자동으로 호출되도록 하
는 디자인 패턴입니다 . RAII 는 코드를 안
전하고 깔끔하게 만듭니다 .
 if-for 문장을 조합하면 , 블록 scope 를
가지는 변수를 , { 안에서만 사용하도록
매크로를 정의할 수 있습니다 .
int2type
template <int I>
struct Int2Type
{
enum { value = I };
};
template <class T, unsigned int N>
class Array : public std::array <T, N>
{
enum AlgoType { NOOP, INSERTION_SORT,
QUICK_SORT };
static const int algo = (N==0) ? NOOP
: (N==1) ? NOOP
: (N<50) ? INSERTION_SORT : QUICK_SORT;
void sort (Int2Type<NOOP>) {}
void sort (Int2Type<INSERTION_SORT>) {}
void sort (Int2Type<QUICK_SORT>) {}
public:
void sort()
{
sort (Int2Type<algo>());
}
11
int main(void)
{
Array<int, 1> a;
a.sort(); // No-op!
Array<int, 400> b;
b.sort(); // Quick sort
}
 컴파일 시간에 정수 상수를 타입
으로 취급하도록 합니다 .
관찰 : sizeof 에 표현식 사용
#include <iostream>
#include <vector>
#include <boost/typeof/typeof.hpp>
#include <boost/mpl/int.hpp>
template<class T>
T type_encoder( T expression_ )
{
return expression_;
}
template<int ID>
struct typeid_wrapper
{
typedef typename extract_type<int_<ID> >::id2type id2type;
typedef typename id2type::type type;
};
12
 함수 템플릿은 파라미터로 전달
된 표현식의 타입을 자동으로
유추하는 역할로 사용할 수 있
습니다 .
 id 로 구분되는 유일한 타입을 생성하고 ,
typeid_wrapper<>::type 으로 접근합니다 .
관찰 : BOOST_TYPEOF 의 원리
#include <iostream>
#include <vector>
#include <boost/typeof/typeof.hpp>
#include <boost/mpl/int.hpp>
…
void main()
{
int i = 1;
sizeof( type_encoder(i+3) );
typeid_wrapper<sizeof( type_encoder(i+3) ) >::type k;
BOOST_TYPEOF( i + 3 ) j;
j = 3;
std::cout << i << std::endl;
std::cout << j << std::endl;
}//main()
13
 sizeof() 에는 type 뿐만 아니라 unary
expression 을 전달할 수 있습니다 .
 함수 호출과 sizeof() 를 이용하면 표현식을
템플릿에 전달할 수 있습니다 .
 이런 원리를 사용하여 구현된 , BOOST_TYPEOF() 는
표현식의 타입을 구합니다 ! i+3 의 타입이 int 이므로
int j; 와 같은 문장입니다 .
응용 예 : KLOCK_BEGIN
KLOCK_DECLARE_INIT( KTest, m_int, (0) );
 
void main()
{
KLOCK_DECLARE( std::vector<int>, vecUserInfo );
std::cout << vecUserInfo.size() << std::endl;
 
//vecUserInfo.push_back( 3 ); // compile time error
//m_int.SetInt( 5 ); // compile time error
 
KLOCK_BEGIN( m_int )
KLOCK_BEGIN( vecUserInfo )
{
m_int.SetInt( 5 );
vecUserInfo.push_back( 5 );
}
std::cout << m_int.GetInt() << std::endl;
std::cout << vecUserInfo.size() << std::endl;
}
 14
 특정한 멤버 변수를 읽는 것은 허용하
되 , 쓰는 동작은 에러가 나도록 할 수
있습니다 .
 KLOCK_DECLARE() 로 선언한 변수는
이러한 특징을 가지도록 합니다 .
 KLOCK_BEGIN() 으로 특정한 변수에
대한 쓰기 권한을 허용할 수 있습니다 .
 이러한 기법은 읽기와 쓰기 동작을 구
분하는 코드를 작성하도록 합니다 .
 변수를 변경할 때 실행되어야 하는 코
드를 지정함으로써 , 여러가지
housekeeping 동작을 숨길 수 있습니
다 .
FOREACH 구현
15
Step1: for- 문장
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <boost/foreach.hpp>
void main()
{
std::vector<int> vecIntData;
vecIntData.push_back( 1 );
vecIntData.push_back( 3 );
for( std::vector<int>::iterator vitor = vecIntData.begin();
vitor != vecIntData.end();
++vitor )
{
int& iData = *vitor;
std::cout << iData << std::endl;
}//for
}//main()
16
 for 문을 이용하여 vector 를
iteration 하는 코드를 작성했습니
다 .
Step2: set_true() 정의하기
bool set_true( bool& bInOutVariable_ )
{
bInOutVariable_ = true;
return false;
}
void main()
{
std::vector<int> vecIntData;
vecIntData.push_back( 1 );
vecIntData.push_back( 3 );
…
17
 set_true() 는 항상 false 를 리턴합니
다 . 인자로 전달된 bool 변수를
true 로 만드는 역할을 합니다 .
Step3: use BOOST_TYPEOF
…
//BOOST_FOREACH( int& iData, vecIntData )
if( bool bForBreaker = false ) {}
else
for( BOOST_TYPEOF(vecIntData)::iterator vitor = vecIntData.begin()
; bForBreaker == false && vitor != vecIntData.end()
; ++vitor )
{
if( set_true(bForBreaker) ) {}
else
for( int& iData = *vitor; bForBreaker == true; bForBreaker = false )
{
std::cout << iData << std::endl;
//break;
}//for
}//for
}//main()
18
 set_true() 는 변수를 항상 true 로 설정하지만 ,
false 를 리턴하므로 , 변수값을 변경하는 일만 합
니다 .
 set_true() 가 필요한 이유는 최종적으로 정의한 매
크로 안에서 break 를 사용했을 때 , break 문장이
바깥 for- 문장을 빠져나가도록 하기 위함입니다 .
Step4: { 를 제거하기
void main()
{
std::vector<int> vecIntData;
vecIntData.push_back( 1 );
vecIntData.push_back( 3 );
//BOOST_FOREACH( int& iData, vecIntData )
if( bool bForBreaker = false ) {}
else
for( BOOST_TYPEOF(vecIntData)::iterator vitor = vecIntData.begin()
; bForBreaker == false && vitor != vecIntData.end()
; ++vitor )
if( set_true(bForBreaker) ) {}
else
for( int& iData = *vitor; bForBreaker == true; bForBreaker = false )
std::cout << iData << std::endl;
}//main()
19
 BOOST_TYPEOF() 를 사용하여 매크
로로 전달된 표현식의 iterator 를 접근
합니다 .
 RAII 구현을 위해서 { 와 } 는 포함되
지 않게 매크로 작성을 준비합니다 .
FOREACH 완성
#define FOREACH( statement_, container_ ) 
if( bool bForBreaker = false ) {} 
else 
for( BOOST_TYPEOF(container_)::iterator vitor = container_.begin() 
; bForBreaker == false && vitor != container_.end() 
; ++vitor ) 
if( set_true(bForBreaker) ) {} 
else 
for( statement_ = *vitor; bForBreaker == true; bForBreaker = false )
void main()
{
std::vector<int> vecIntData;
vecIntData.push_back( 1 );
vecIntData.push_back( 3 );
FOREACH( int& iData, vecIntData )
{
std::cout << iData << std::endl;
//break;
}//FOREACH()
}//main()
20
 중첩된 FOREACH() 와 배열을 지원하기
위해서는 추가적인 처리가 필요합니다 .
응용 예 : ASSET_FOREACH
 기본적으로 구현한 FOREACH() 를 응용하여 , 프로그
램의 내부 로직에 의존적인 여러가지 매크로를 정의
할 수 있습니다 .
– 프로그램에서 현재 관리중인 모든 asset 들에 대한 커스텀
iteration 을 작성할 수 있습니다 .
– .xml 파일을 로드하고 나서 , 모든 element 에 대한 커스텀
iteration 을 작성할 수 있습니다 .
– 프로그램에서 현재 생성된 모든 게임 객체에 대한 커스텀 iteration
을 작성할 수 있습니다 .
21
shared_ptr 의 내부 구조
22
void 참조를 특화로 구현
23
template<class T> struct shared_ptr_traits
{
typedef T& reference;
};
template<> struct shared_ptr_traits<void>
{
typedef void reference;
};
 void 타입에 대한 reference 가 가능하도록
템플릿 특화 specialization 을 사용하여 미
리 구현해 둡니다 .
 기타 type-trait 에 대한 설명은 생략합니다 .
shared_ptr: 생성자 구현
24
template<class T> class shared_ptr
{
public:
typedef shared_ptr<T> this_type;
typedef T value_type;
typedef T* pointer;
typedef typename shared_ptr_traits<T>::reference reference;
public:
shared_ptr(T * p = 0) : px(p), pn(0)
{
if( px != NULL )
pn = new int(1);
}
 생성자에서는 전달받은 raw pointer 를 초
기화합니다 .
 참조 카운팅을 위한 메모리 할당을 하고 ,
참조 카운터를 1 로 초기화합니다 .
shared_ptr: 복사 생성자와 파괴자 구현
25
shared_ptr( const shared_ptr& right_ ) : px( 0 ), pn( 0 )
{
release();
px = right_.px;
pn = right_.pn;
if( px != NULL )
*pn += 1;
}
~shared_ptr()
{
release();
}
 복사 생성자는 먼저 이전에 할당되어 있는
리소스를 해제 합니다 .
 새로운 리소스에 대한 참조를 설정하고 ,
참조 카운터를 증가시킵니다 .
shared_ptr: operator=(), operator pointer()
26
shared_ptr& operator=( const shared_ptr& right_ )
{
release();
px = right_.px;
pn = right_.pn;
if( px != NULL )
*pn += 1;
return *this;
}
operator pointer() const
{
return px;
}
 대입 연산자는 복사 생성자와 거의 동일하
게 구현합니다 .
 타입에 대한 포인터 연산이 제대로 동작하
도록 operator T*() 를 정의합니다 .
shared_ptr: release() 구현
27
void release()
{
if( px != NULL && *pn >= 1 )
{
*pn -= 1;
if( *pn == 0 )
{
delete px;
px = NULL;
delete pn;
pn = NULL;
}//if
}//if
px = NULL;
pn = NULL;
}
 release() 는 먼저 참조 카운터를 감소합니
다 .
 참조 카운터가 0 이되면 , 실제 리소스를
해제 합니다 .
shared_ptr: reset(), use_count() 구현
28
void reset()
{
release();
}
void reset(T * p)
{
release();
px = p;
pn = NULL;
if( px != NULL )
pn = new int(1);
}
int use_count() const { return *pn; }
 reset() 은 해제 후 할당과 동일합니다 .
 완성된 shared_ptr 은 암시적 생성 implicit
construction 을 지원하지 않으므로 , reset()
구현이 반드시 필요합니다 .
 use_count() 는 현재 참조 카운터를 리턴합
니다 .
shared_ptr: operator*(), operator->() 구현
29
reference operator*() const // never throws
{
return *px;
}
T* operator->() const // never throws
{
return px;
}
private:
T* px;
int* pn;
};//template<class T> class shared_ptr
 간접지정 연산자와 화살표 연산자가 제대
로 동작하도록 함수를 작성합니다 .
 void* 에 대한 참조가 동작하도록 하기 위해
서는 void 에 대한 참조를 템플릿 특화로 미
리 구현해 두어야 합니다 .
main() 에서 테스트
30
int main()
{
typedef shared_ptr<int> IntPtr;
IntPtr spInt = new int(3); // spInt.use_count() == 1
if( spInt != NULL )
{
std::cout << *spInt << std::endl; // 3
}//if
IntPtr spInt2 = spInt; // spInt.use_count() == 2
IntPtr spInt3 = spInt; // spInt.use_count() == 3
spInt.reset( new int(4) ); // spInt.use_count() == 1
*spInt = 5; // 3 changed to 5
if( spInt2 != NULL ) // spInt2.use_count() == 2
{
std::cout << *spInt2 << std::endl; // 3
}//if
return 0;
}//int main()
copy-and-swap: swap() 메서드 구현
31
void swap( shared_ptr<T>& right_ ) // never throws
{
std::swap( px, right_.px );
std::swap( pn, right_.pn );
}
 exception safety
1) Basic: component 의 invariant 는 보존되고 , resource
leak 은 발생하지 않아야 합니다 .
2) Strong: 성공적으로 완료되었던지 예외를 던졌던
지 둘 중의 하나여야 합니다 .
3) No-throw: 예외를 던지지 않아야 합니다 .
 copy-and-swap 을 지원하기 위해서 shared_ptr 의
swap() 은 예외를 던지지 않도록 구현해야 합니다 .
shared_ptr: swap() 을 반영한 수정
32
shared_ptr& operator=( const shared_ptr& right_ )
{
//release();
//px = right_.px;
//pn = right_.pn;
//if( px != NULL )
// *pn += 1;
this_type(right_).swap(*this);
return *this;
}
void reset(T * p)
{
//release();
//px = p;
//pn = NULL;
//if( px != NULL )
// pn = new int(1);
this_type(p).swap(*this);
}
관찰 : if 의 조건문 표현식
33
class KBoolTest
{
public:
operator bool() const { return true; }
operator int() const { return 1; }
operator int*() const { return NULL; }
int GetValue() const { return 9; }
};
int main()
{
KBoolTest t;
if( t )
std::cout << t.GetValue() << std::endl;
return 0;
}//int main()
 if 문의 조건은 일반적인 bool 표현식이 아닌
C 가 허용하는 참인 조건식을 적을 수 있습니다
.
 평가의 partial order 의 순서는 bool  native
type  pointer 의 순입니다 .
safe bool idiom
34
//int* p = spInt; // (1)
//if( spInt < spInt ) // (2)
//{
//}  지금까지의 구현은 (1) 과 (2) 처럼 잘못된 사
용이나 , 의미없는 bool 표현식을 막지 못
합니다 .
  template <typename T> void some_func(const T& t) {
    if (t)   
      t->print();
  }
 smart pointer T 에 대해 이 문장이 동작
하려면 T 는 bool 형에 대한 형 변환 연
산자를 제공해야 합니다 .
해결시도 1: operator bool() 구현
35
class Testable {
    bool ok_;
  public:
    explicit Testable(bool b=true):ok_(b) {}
 
    operator bool() const {
      return ok_;
    }
  };  shared_ptr 은 자신이 valid 한 raw pointer 를 가질 때 ,
true 를 리턴하는 operator bool() 을 작성할 수 있습니다 .
operator bool() cont.
36
test << 1; // (1)
  int i=test; // (2)
  Testable a;
  AnotherTestable b;
 
  if (a==b) { // (3)
  }
 
  if (a<b) { // (4)
  }
 이 구현은 (1), (2) 같은 의미 없는 문장
이나 , (3), (4) 같은 의미 없는 bool 검
사를 막지 못합니다 .
해결시도 2: operator void*() 구현
37
 operator void*() const {
    return ok_==true ? this : 0;
  }
 이 구현은 영리해 보이지만 , 아래의 문장처럼
delete 를 직접호출 할 수 있는 약점을 가집니다 .
Testable test;
delete test;
해결시도 3: nested class
38
class Testable {
    bool ok_;
  public:
    explicit Testable(bool b=true):ok_(b) {}
 
    class nested_class;
 
    operator const nested_class*() const {
      return ok_ ? reinterpret_cast<const nested_class*>(this) : 0;
    }
  };
Testable b1,b2;
 
  if (b1==b2) {
  }
 
  if (b1<b2) {
  }
 safe bool 을 위한 nested class 구현 역시 의미없는 bool 검
사를 막지 못합니다 .
 이 문제를 해결하려면 포인터 형변환이 되지만 , < 같은 비교
연산자를 지원하지 않는 데이터 타입을 사용하는 것입니다 .
 흥미롭게도 멤버 함수에 대한 포인터가 그렇게 동작합
니다 !
최종 버전 : safe bool idiom
39
class Testable {
    bool ok_;
    typedef void (Testable::*bool_type)() const;
    void this_type_does_not_support_comparisons() const {}
  public:
    explicit Testable(bool b=true):ok_(b) {}
 
    operator bool_type() const {
      return ok_==true ?
        &Testable::this_type_does_not_support_comparisons : 0;
    }
  };
 if- 문장의 조건 표현식에 포인터가 사용될 수
있는 점을 이용하여 , 함수 포인터를 리턴하
는 연산자 함수를 정의합니다 .
shared_ptr 의 내부 : unspecified_bool_type 사용
40
//operator pointer() const
//{
// return px;
//}
void unspecified_bool() const
{
}
typedef void (shared_ptr::*unspecified_bool_type)() const;
operator unspecified_bool_type() const // never throws
{
return px == 0 ? 0 : &shared_ptr::unspecified_bool;
}
 boost 의 실제 코드는
unspecified_bool_type() 을 사용합니다 .
 C++ 표준 라이브러리 뿐만 아니라 , 게임
엔진의 스마트 포인터 구현은 모두 이러한
기법을 사용합니다 .
shared_ptr 에 적용된 safe bool idiom
41
typedef shared_ptr<int> IntPtr;
IntPtr spInt = new int(3);
IntPtr spInt2 = spInt;
IntPtr spInt3 = spInt;
spInt.reset( new int(4) );
*spInt = 5;
if( spInt2 != NULL )
{
std::cout << *spInt << std::endl;
}//if
int* p = spInt; // (1) error
if( spInt2 < spInt3 ) // (2) error
{
}
 이제 (1) 과 (2) 같은 의미 없는 문
장은 컴파일 시간 에러가 발생합
니다 .
implicit constructor 문제 해결하기
42
void Test( shared_ptr<int> spInt_ )
{
}
int iData = 5;
Test( &iData );
 실제 포인터가 아닌 , 포인터 표현식에 대한
shared_ptr 생성을 막을 필요가 있습니다 .
 이 문제에 대한 해결방법은 명시적 생성만 가능하도록
클래스를 설계하는 것입니다 .
explicit shared_ptr(T * p = 0) : px(p), pn(0)
{
if( px != NULL )
pn = new int(1);
}
boost::weak_ptr 과 RAII 결합
43
weak_ptr<T>
44
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
class Test;
typedef boost::shared_ptr<Test> TestPtr;
typedef boost::weak_ptr<Test> TestWeakPtr;
class Test
{
public:
 shared_ptr 을 제공할 때 , 포인터 순환 참
조 문제등을 해결하기 위해서 weak_ptr 을
함께 제공합니다 .
weak_ptr<T> cont.
45
class TestRef
{
public:
TestRef(){}
void SetTest( TestPtr tp )
{
m_tp = tp;
}
void Print() const
{
if( TestPtr tp = m_tp.lock() )
{
tp->Print();
}
}
private:
TestWeakPtr m_tp;
};
 weak_ptr 을 사용하는 경우 , 지금 사용해
도 안전한 실제 포인터를 얻기 위해서
lock() 을 호출합니다 .
int main()
{
TestPtr tp = Test::CreateTest( 1 );
TestRef ref;
ref.SetTest( tp );
tp.reset();
ref.Print();
}//int main()
weak_ptr<T> lock()
46
 weak_ptr<T> 의 lock() 구현
shared_ptr<T, A, D> lock() const // never throws
{
// optimization: avoid throw overhead
if(expired()){
return shared_ptr<element_type, A, D>();
}
BOOST_TRY{
return shared_ptr<element_type, A, D>(*this);
}
}
 shared_ptr<T>( weak_ptr<Y> ) 구현
template<class Y>
explicit shared_ptr(weak_ptr<Y> const & r): pn(r.pn) // may throw
{
// it is now safe to copy r.px, as pn(r.pn) did not throw
px = r.px;
}
raw pointer 에서 shared_ptr 얻기 : factory
47
class X
{
private:
X() { ... }
public:
static shared_ptr<X> create()
{
shared_ptr<X> px(new X);
// use px as 'this_'
return px;
}
};
 shared_ptr<T> 로 관리되지 않는 raw 포
인터에서 shared_ptr<T> 을 얻을 필요가
있습니다 .
 클래스 객체가 shared_ptr<T> 로 관리되
더라도 , 생성자에서 shared_ptr<T> 를 얻
을 방법도 없습니다 .
 해결 방법은 weak_ptr 과 팩토리 함수를
사용하는 것입니다 .
factory: this 에 대한 shared_ptr<T>
48
class impl: public X, public Y
{
private:
weak_ptr<impl> weak_this;
impl(impl const &);
impl & operator=(impl const &);
impl() { ... }
public:
static shared_ptr<impl> create()
{
shared_ptr<impl> pi(new impl);
pi->weak_this = pi; // (1) 팩토리에서 weak_ptr<T> 을 초기화 해 놓습니다 .
return pi;
}
virtual void f() { ... }
virtual shared_ptr<X> getX()
{
shared_ptr<X> px(weak_this);
return px;
}
};
 대상 객체를 생성할 때 , weak_ptr 이 적절
하게 초기화되도록 합니다 .
 그러면 , 후에 필요하면 대상 객체에 대한
shared_ptr 을 얻을 수 있습니다 .
boost::enable_shared_from_this<T>
49
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
class Test;
typedef boost::shared_ptr<Test> TestPtr;
class Test : public boost::enable_shared_from_this<Test>
{
public:
static TestPtr CreateTest(int i)
{
TestPtr sp( new Test( i ) );
return sp;
}
Test(int i) : m_i(i) {}
void Print() const
{
std::cout << m_i << std::endl;
}
private:
int m_i;
};
 이 역할을 하는 boost 의 베이스 클래스가
enabled_shared_from_this 입니다 .
shared_from_this()
50
void TestFun( Test* pt )
{
TestPtr tp;
if( pt != NULL )
tp = pt->shared_from_this();
if( tp != NULL )
{
tp->Print();
}
}
 Test 가 enable_shared_from_this 를 상속받은 경ㅇ
우 , raw pointer 에서 shared_ptr 을 얻기 위해서는
shared_from_this() 를 호출합니다 .
응용 예 : RAII
51
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/typeof/typeof.hpp>
#define KSmartPointer(type_) 
class type_; 
typedef boost::shared_ptr<type_> type_##SharedPtr; 
typedef boost::weak_ptr<type_> type_##WeakPtr;
#define IF_MEMBER_WEAKPTR( member_name_ )
if( boost::shared_ptr<BOOST_TYPEOF(member_name_)::element_type> member_name_ = this-
>member_name_.lock() )
 게임 객체가 관리되는 리소스가 있는 경우에만 사용하려
고 하는 경우 , 리소스에 대한 weak_ptr 을 멤버로 가집니
다 .
 게임 객체가 실제 객체를 사용하려고 하면 , lock() 호출이
필요합니다 .
 이러한 패턴을 RAII 매크로로 작성했습니다 .
응용 예 cont.
52
class TestContainer
{
public:
TestContainer(){}
void SetTest( TestSharedPtr tp )
{
m_tp = tp;
}
void Print() const
{
IF_MEMBER_WEAKPTR( m_tp )
{
m_tp->Print();
}//if
}
private:
TestWeakPtr m_tp;
};
 IF_MEMBER_WEAKPTR() 은 RAII 스타일의 매크
로로 멤버에 대한 안전한 접근을 보장합니다 .
질문과 대답
53
참고자료
 http://www.boost.org/doc/libs/1_35_0/libs/type_tra
 http://www.boost.org/doc/libs/1_37_0/libs/smart_pt
 http://www.artima.com/cppsource/safebool.html
54

Weitere ähnliche Inhalte

Was ist angesagt?

Modern C++ 프로그래머를 위한 CPP11/14 핵심
Modern C++ 프로그래머를 위한 CPP11/14 핵심Modern C++ 프로그래머를 위한 CPP11/14 핵심
Modern C++ 프로그래머를 위한 CPP11/14 핵심흥배 최
 
C#을 사용한 빠른 툴 개발
C#을 사용한 빠른 툴 개발C#을 사용한 빠른 툴 개발
C#을 사용한 빠른 툴 개발흥배 최
 
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로Jaeseung Ha
 
파이썬 스터디 9장
파이썬 스터디 9장파이썬 스터디 9장
파이썬 스터디 9장SeongHyun Ahn
 
[C++ Korea 2nd Seminar] C++17 Key Features Summary
[C++ Korea 2nd Seminar] C++17 Key Features Summary[C++ Korea 2nd Seminar] C++17 Key Features Summary
[C++ Korea 2nd Seminar] C++17 Key Features SummaryChris Ohk
 
20150212 c++11 features used in crow
20150212 c++11 features used in crow20150212 c++11 features used in crow
20150212 c++11 features used in crowJaeseung Ha
 
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)Sang Don Kim
 
Javascript개발자의 눈으로 python 들여다보기
Javascript개발자의 눈으로 python 들여다보기Javascript개발자의 눈으로 python 들여다보기
Javascript개발자의 눈으로 python 들여다보기지수 윤
 
프로그래밍 대회: C++11 이야기
프로그래밍 대회: C++11 이야기프로그래밍 대회: C++11 이야기
프로그래밍 대회: C++11 이야기Jongwook Choi
 
GopherCon Korea 2015 - Python 개발자를 위한 Go (이경찬)
GopherCon Korea 2015 - Python 개발자를 위한 Go (이경찬)GopherCon Korea 2015 - Python 개발자를 위한 Go (이경찬)
GopherCon Korea 2015 - Python 개발자를 위한 Go (이경찬)Kyoungchan Lee
 
Refelction의 개념과 RTTR 라이브러리
Refelction의 개념과 RTTR 라이브러리Refelction의 개념과 RTTR 라이브러리
Refelction의 개념과 RTTR 라이브러리ssuser7c5a40
 
사례를 통해 살펴보는 프로파일링과 최적화 NDC2013
사례를 통해 살펴보는 프로파일링과 최적화 NDC2013사례를 통해 살펴보는 프로파일링과 최적화 NDC2013
사례를 통해 살펴보는 프로파일링과 최적화 NDC2013Esun Kim
 
Python vs Java @ PyCon Korea 2017
Python vs Java @ PyCon Korea 2017Python vs Java @ PyCon Korea 2017
Python vs Java @ PyCon Korea 2017Insuk (Chris) Cho
 
니름: 쉬운 SOA 단위 테스트
니름: 쉬운 SOA 단위 테스트니름: 쉬운 SOA 단위 테스트
니름: 쉬운 SOA 단위 테스트효준 강
 
[C++ Korea 3rd Seminar] 새 C++은 새 Visual Studio에, 좌충우돌 마이그레이션 이야기
[C++ Korea 3rd Seminar] 새 C++은 새 Visual Studio에, 좌충우돌 마이그레이션 이야기[C++ Korea 3rd Seminar] 새 C++은 새 Visual Studio에, 좌충우돌 마이그레이션 이야기
[C++ Korea 3rd Seminar] 새 C++은 새 Visual Studio에, 좌충우돌 마이그레이션 이야기Chris Ohk
 
Let's Go (golang)
Let's Go (golang)Let's Go (golang)
Let's Go (golang)상욱 송
 
모두의 JIT 컴파일러
모두의 JIT 컴파일러모두의 JIT 컴파일러
모두의 JIT 컴파일러우경 성
 
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitive
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitive[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitive
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitiveNAVER D2
 

Was ist angesagt? (20)

Modern C++ 프로그래머를 위한 CPP11/14 핵심
Modern C++ 프로그래머를 위한 CPP11/14 핵심Modern C++ 프로그래머를 위한 CPP11/14 핵심
Modern C++ 프로그래머를 위한 CPP11/14 핵심
 
C#을 사용한 빠른 툴 개발
C#을 사용한 빠른 툴 개발C#을 사용한 빠른 툴 개발
C#을 사용한 빠른 툴 개발
 
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
 
파이썬 스터디 9장
파이썬 스터디 9장파이썬 스터디 9장
파이썬 스터디 9장
 
[C++ Korea 2nd Seminar] C++17 Key Features Summary
[C++ Korea 2nd Seminar] C++17 Key Features Summary[C++ Korea 2nd Seminar] C++17 Key Features Summary
[C++ Korea 2nd Seminar] C++17 Key Features Summary
 
20150212 c++11 features used in crow
20150212 c++11 features used in crow20150212 c++11 features used in crow
20150212 c++11 features used in crow
 
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
 
Javascript개발자의 눈으로 python 들여다보기
Javascript개발자의 눈으로 python 들여다보기Javascript개발자의 눈으로 python 들여다보기
Javascript개발자의 눈으로 python 들여다보기
 
프로그래밍 대회: C++11 이야기
프로그래밍 대회: C++11 이야기프로그래밍 대회: C++11 이야기
프로그래밍 대회: C++11 이야기
 
GopherCon Korea 2015 - Python 개발자를 위한 Go (이경찬)
GopherCon Korea 2015 - Python 개발자를 위한 Go (이경찬)GopherCon Korea 2015 - Python 개발자를 위한 Go (이경찬)
GopherCon Korea 2015 - Python 개발자를 위한 Go (이경찬)
 
요즘웹개발
요즘웹개발요즘웹개발
요즘웹개발
 
Refelction의 개념과 RTTR 라이브러리
Refelction의 개념과 RTTR 라이브러리Refelction의 개념과 RTTR 라이브러리
Refelction의 개념과 RTTR 라이브러리
 
파이선 실전공략-1
파이선 실전공략-1파이선 실전공략-1
파이선 실전공략-1
 
사례를 통해 살펴보는 프로파일링과 최적화 NDC2013
사례를 통해 살펴보는 프로파일링과 최적화 NDC2013사례를 통해 살펴보는 프로파일링과 최적화 NDC2013
사례를 통해 살펴보는 프로파일링과 최적화 NDC2013
 
Python vs Java @ PyCon Korea 2017
Python vs Java @ PyCon Korea 2017Python vs Java @ PyCon Korea 2017
Python vs Java @ PyCon Korea 2017
 
니름: 쉬운 SOA 단위 테스트
니름: 쉬운 SOA 단위 테스트니름: 쉬운 SOA 단위 테스트
니름: 쉬운 SOA 단위 테스트
 
[C++ Korea 3rd Seminar] 새 C++은 새 Visual Studio에, 좌충우돌 마이그레이션 이야기
[C++ Korea 3rd Seminar] 새 C++은 새 Visual Studio에, 좌충우돌 마이그레이션 이야기[C++ Korea 3rd Seminar] 새 C++은 새 Visual Studio에, 좌충우돌 마이그레이션 이야기
[C++ Korea 3rd Seminar] 새 C++은 새 Visual Studio에, 좌충우돌 마이그레이션 이야기
 
Let's Go (golang)
Let's Go (golang)Let's Go (golang)
Let's Go (golang)
 
모두의 JIT 컴파일러
모두의 JIT 컴파일러모두의 JIT 컴파일러
모두의 JIT 컴파일러
 
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitive
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitive[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitive
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitive
 

Ähnlich wie Boost라이브러리의내부구조 20151111 서진택

불어오는 변화의 바람, From c++98 to c++11, 14
불어오는 변화의 바람, From c++98 to c++11, 14 불어오는 변화의 바람, From c++98 to c++11, 14
불어오는 변화의 바람, From c++98 to c++11, 14 명신 김
 
Visual studio 2010
Visual studio 2010Visual studio 2010
Visual studio 2010MinGeun Park
 
[NDC2016] TERA 서버의 Modern C++ 활용기
[NDC2016] TERA 서버의 Modern C++ 활용기[NDC2016] TERA 서버의 Modern C++ 활용기
[NDC2016] TERA 서버의 Modern C++ 활용기Sang Heon Lee
 
카사 공개세미나1회 W.E.L.C.
카사 공개세미나1회  W.E.L.C.카사 공개세미나1회  W.E.L.C.
카사 공개세미나1회 W.E.L.C.Ryan Park
 
Effective c++(chapter 5,6)
Effective c++(chapter 5,6)Effective c++(chapter 5,6)
Effective c++(chapter 5,6)문익 장
 
C++20 Key Features Summary
C++20 Key Features SummaryC++20 Key Features Summary
C++20 Key Features SummaryChris Ohk
 
Api design for c++ 6장
Api design for c++ 6장Api design for c++ 6장
Api design for c++ 6장Ji Hun Kim
 
Ai C#세미나
Ai C#세미나Ai C#세미나
Ai C#세미나Astin Choi
 
About Visual C++ 10
About  Visual C++ 10About  Visual C++ 10
About Visual C++ 10흥배 최
 
C++17 Key Features Summary - Ver 2
C++17 Key Features Summary - Ver 2C++17 Key Features Summary - Ver 2
C++17 Key Features Summary - Ver 2Chris Ohk
 
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기Chris Ohk
 
More effective c++ chapter1 2_dcshin
More effective c++ chapter1 2_dcshinMore effective c++ chapter1 2_dcshin
More effective c++ chapter1 2_dcshinDong Chan Shin
 
7가지 동시성 모델 - 데이터 병렬성
7가지 동시성 모델 - 데이터 병렬성7가지 동시성 모델 - 데이터 병렬성
7가지 동시성 모델 - 데이터 병렬성HyeonSeok Choi
 
[0618구경원]초보 게임프로그래머를 위한 c++
[0618구경원]초보 게임프로그래머를 위한 c++[0618구경원]초보 게임프로그래머를 위한 c++
[0618구경원]초보 게임프로그래머를 위한 c++KyeongWon Koo
 

Ähnlich wie Boost라이브러리의내부구조 20151111 서진택 (20)

불어오는 변화의 바람, From c++98 to c++11, 14
불어오는 변화의 바람, From c++98 to c++11, 14 불어오는 변화의 바람, From c++98 to c++11, 14
불어오는 변화의 바람, From c++98 to c++11, 14
 
Visual studio 2010
Visual studio 2010Visual studio 2010
Visual studio 2010
 
[NDC2016] TERA 서버의 Modern C++ 활용기
[NDC2016] TERA 서버의 Modern C++ 활용기[NDC2016] TERA 서버의 Modern C++ 활용기
[NDC2016] TERA 서버의 Modern C++ 활용기
 
카사 공개세미나1회 W.E.L.C.
카사 공개세미나1회  W.E.L.C.카사 공개세미나1회  W.E.L.C.
카사 공개세미나1회 W.E.L.C.
 
강의자료4
강의자료4강의자료4
강의자료4
 
Effective c++(chapter 5,6)
Effective c++(chapter 5,6)Effective c++(chapter 5,6)
Effective c++(chapter 5,6)
 
06장 함수
06장 함수06장 함수
06장 함수
 
6 function
6 function6 function
6 function
 
C++20 Key Features Summary
C++20 Key Features SummaryC++20 Key Features Summary
C++20 Key Features Summary
 
HI-ARC PS 101
HI-ARC PS 101HI-ARC PS 101
HI-ARC PS 101
 
Api design for c++ 6장
Api design for c++ 6장Api design for c++ 6장
Api design for c++ 6장
 
Ai C#세미나
Ai C#세미나Ai C#세미나
Ai C#세미나
 
About Visual C++ 10
About  Visual C++ 10About  Visual C++ 10
About Visual C++ 10
 
C++17 Key Features Summary - Ver 2
C++17 Key Features Summary - Ver 2C++17 Key Features Summary - Ver 2
C++17 Key Features Summary - Ver 2
 
Object C - RIP
Object C - RIPObject C - RIP
Object C - RIP
 
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
 
More effective c++ chapter1 2_dcshin
More effective c++ chapter1 2_dcshinMore effective c++ chapter1 2_dcshin
More effective c++ chapter1 2_dcshin
 
7가지 동시성 모델 - 데이터 병렬성
7가지 동시성 모델 - 데이터 병렬성7가지 동시성 모델 - 데이터 병렬성
7가지 동시성 모델 - 데이터 병렬성
 
[0618구경원]초보 게임프로그래머를 위한 c++
[0618구경원]초보 게임프로그래머를 위한 c++[0618구경원]초보 게임프로그래머를 위한 c++
[0618구경원]초보 게임프로그래머를 위한 c++
 
W14 chap13
W14 chap13W14 chap13
W14 chap13
 

Mehr von JinTaek Seo

Neural network 20161210_jintaekseo
Neural network 20161210_jintaekseoNeural network 20161210_jintaekseo
Neural network 20161210_jintaekseoJinTaek Seo
 
05 heap 20161110_jintaeks
05 heap 20161110_jintaeks05 heap 20161110_jintaeks
05 heap 20161110_jintaeksJinTaek Seo
 
02 linked list_20160217_jintaekseo
02 linked list_20160217_jintaekseo02 linked list_20160217_jintaekseo
02 linked list_20160217_jintaekseoJinTaek Seo
 
Hermite spline english_20161201_jintaeks
Hermite spline english_20161201_jintaeksHermite spline english_20161201_jintaeks
Hermite spline english_20161201_jintaeksJinTaek Seo
 
01 stack 20160908_jintaek_seo
01 stack 20160908_jintaek_seo01 stack 20160908_jintaek_seo
01 stack 20160908_jintaek_seoJinTaek Seo
 
03 fsm how_toimplementai_state_20161006_jintaeks
03 fsm how_toimplementai_state_20161006_jintaeks03 fsm how_toimplementai_state_20161006_jintaeks
03 fsm how_toimplementai_state_20161006_jintaeksJinTaek Seo
 
Beginning direct3d gameprogramming10_shaderdetail_20160506_jintaeks
Beginning direct3d gameprogramming10_shaderdetail_20160506_jintaeksBeginning direct3d gameprogramming10_shaderdetail_20160506_jintaeks
Beginning direct3d gameprogramming10_shaderdetail_20160506_jintaeksJinTaek Seo
 
Beginning direct3d gameprogramming09_shaderprogramming_20160505_jintaeks
Beginning direct3d gameprogramming09_shaderprogramming_20160505_jintaeksBeginning direct3d gameprogramming09_shaderprogramming_20160505_jintaeks
Beginning direct3d gameprogramming09_shaderprogramming_20160505_jintaeksJinTaek Seo
 
Beginning direct3d gameprogramming08_usingtextures_20160428_jintaeks
Beginning direct3d gameprogramming08_usingtextures_20160428_jintaeksBeginning direct3d gameprogramming08_usingtextures_20160428_jintaeks
Beginning direct3d gameprogramming08_usingtextures_20160428_jintaeksJinTaek Seo
 
Beginning direct3d gameprogramming07_lightsandmaterials_20161117_jintaeks
Beginning direct3d gameprogramming07_lightsandmaterials_20161117_jintaeksBeginning direct3d gameprogramming07_lightsandmaterials_20161117_jintaeks
Beginning direct3d gameprogramming07_lightsandmaterials_20161117_jintaeksJinTaek Seo
 
Beginning direct3d gameprogramming06_firststepstoanimation_20161115_jintaeks
Beginning direct3d gameprogramming06_firststepstoanimation_20161115_jintaeksBeginning direct3d gameprogramming06_firststepstoanimation_20161115_jintaeks
Beginning direct3d gameprogramming06_firststepstoanimation_20161115_jintaeksJinTaek Seo
 
Beginning direct3d gameprogramming05_thebasics_20160421_jintaeks
Beginning direct3d gameprogramming05_thebasics_20160421_jintaeksBeginning direct3d gameprogramming05_thebasics_20160421_jintaeks
Beginning direct3d gameprogramming05_thebasics_20160421_jintaeksJinTaek Seo
 
Beginning direct3d gameprogramming04_3dfundamentals_20160414_jintaeks
Beginning direct3d gameprogramming04_3dfundamentals_20160414_jintaeksBeginning direct3d gameprogramming04_3dfundamentals_20160414_jintaeks
Beginning direct3d gameprogramming04_3dfundamentals_20160414_jintaeksJinTaek Seo
 
Beginning direct3d gameprogramming02_overviewofhalandcom_20160408_jintaeks
Beginning direct3d gameprogramming02_overviewofhalandcom_20160408_jintaeksBeginning direct3d gameprogramming02_overviewofhalandcom_20160408_jintaeks
Beginning direct3d gameprogramming02_overviewofhalandcom_20160408_jintaeksJinTaek Seo
 
Beginning direct3d gameprogramming01_thehistoryofdirect3dgraphics_20160407_ji...
Beginning direct3d gameprogramming01_thehistoryofdirect3dgraphics_20160407_ji...Beginning direct3d gameprogramming01_thehistoryofdirect3dgraphics_20160407_ji...
Beginning direct3d gameprogramming01_thehistoryofdirect3dgraphics_20160407_ji...JinTaek Seo
 
Beginning direct3d gameprogramming01_20161102_jintaeks
Beginning direct3d gameprogramming01_20161102_jintaeksBeginning direct3d gameprogramming01_20161102_jintaeks
Beginning direct3d gameprogramming01_20161102_jintaeksJinTaek Seo
 
Beginning direct3d gameprogramming03_programmingconventions_20160414_jintaeks
Beginning direct3d gameprogramming03_programmingconventions_20160414_jintaeksBeginning direct3d gameprogramming03_programmingconventions_20160414_jintaeks
Beginning direct3d gameprogramming03_programmingconventions_20160414_jintaeksJinTaek Seo
 
Beginning direct3d gameprogrammingmath06_transformations_20161019_jintaeks
Beginning direct3d gameprogrammingmath06_transformations_20161019_jintaeksBeginning direct3d gameprogrammingmath06_transformations_20161019_jintaeks
Beginning direct3d gameprogrammingmath06_transformations_20161019_jintaeksJinTaek Seo
 
Beginning direct3d gameprogrammingmath05_matrices_20160515_jintaeks
Beginning direct3d gameprogrammingmath05_matrices_20160515_jintaeksBeginning direct3d gameprogrammingmath05_matrices_20160515_jintaeks
Beginning direct3d gameprogrammingmath05_matrices_20160515_jintaeksJinTaek Seo
 
Beginning direct3d gameprogrammingmath04_calculus_20160324_jintaeks
Beginning direct3d gameprogrammingmath04_calculus_20160324_jintaeksBeginning direct3d gameprogrammingmath04_calculus_20160324_jintaeks
Beginning direct3d gameprogrammingmath04_calculus_20160324_jintaeksJinTaek Seo
 

Mehr von JinTaek Seo (20)

Neural network 20161210_jintaekseo
Neural network 20161210_jintaekseoNeural network 20161210_jintaekseo
Neural network 20161210_jintaekseo
 
05 heap 20161110_jintaeks
05 heap 20161110_jintaeks05 heap 20161110_jintaeks
05 heap 20161110_jintaeks
 
02 linked list_20160217_jintaekseo
02 linked list_20160217_jintaekseo02 linked list_20160217_jintaekseo
02 linked list_20160217_jintaekseo
 
Hermite spline english_20161201_jintaeks
Hermite spline english_20161201_jintaeksHermite spline english_20161201_jintaeks
Hermite spline english_20161201_jintaeks
 
01 stack 20160908_jintaek_seo
01 stack 20160908_jintaek_seo01 stack 20160908_jintaek_seo
01 stack 20160908_jintaek_seo
 
03 fsm how_toimplementai_state_20161006_jintaeks
03 fsm how_toimplementai_state_20161006_jintaeks03 fsm how_toimplementai_state_20161006_jintaeks
03 fsm how_toimplementai_state_20161006_jintaeks
 
Beginning direct3d gameprogramming10_shaderdetail_20160506_jintaeks
Beginning direct3d gameprogramming10_shaderdetail_20160506_jintaeksBeginning direct3d gameprogramming10_shaderdetail_20160506_jintaeks
Beginning direct3d gameprogramming10_shaderdetail_20160506_jintaeks
 
Beginning direct3d gameprogramming09_shaderprogramming_20160505_jintaeks
Beginning direct3d gameprogramming09_shaderprogramming_20160505_jintaeksBeginning direct3d gameprogramming09_shaderprogramming_20160505_jintaeks
Beginning direct3d gameprogramming09_shaderprogramming_20160505_jintaeks
 
Beginning direct3d gameprogramming08_usingtextures_20160428_jintaeks
Beginning direct3d gameprogramming08_usingtextures_20160428_jintaeksBeginning direct3d gameprogramming08_usingtextures_20160428_jintaeks
Beginning direct3d gameprogramming08_usingtextures_20160428_jintaeks
 
Beginning direct3d gameprogramming07_lightsandmaterials_20161117_jintaeks
Beginning direct3d gameprogramming07_lightsandmaterials_20161117_jintaeksBeginning direct3d gameprogramming07_lightsandmaterials_20161117_jintaeks
Beginning direct3d gameprogramming07_lightsandmaterials_20161117_jintaeks
 
Beginning direct3d gameprogramming06_firststepstoanimation_20161115_jintaeks
Beginning direct3d gameprogramming06_firststepstoanimation_20161115_jintaeksBeginning direct3d gameprogramming06_firststepstoanimation_20161115_jintaeks
Beginning direct3d gameprogramming06_firststepstoanimation_20161115_jintaeks
 
Beginning direct3d gameprogramming05_thebasics_20160421_jintaeks
Beginning direct3d gameprogramming05_thebasics_20160421_jintaeksBeginning direct3d gameprogramming05_thebasics_20160421_jintaeks
Beginning direct3d gameprogramming05_thebasics_20160421_jintaeks
 
Beginning direct3d gameprogramming04_3dfundamentals_20160414_jintaeks
Beginning direct3d gameprogramming04_3dfundamentals_20160414_jintaeksBeginning direct3d gameprogramming04_3dfundamentals_20160414_jintaeks
Beginning direct3d gameprogramming04_3dfundamentals_20160414_jintaeks
 
Beginning direct3d gameprogramming02_overviewofhalandcom_20160408_jintaeks
Beginning direct3d gameprogramming02_overviewofhalandcom_20160408_jintaeksBeginning direct3d gameprogramming02_overviewofhalandcom_20160408_jintaeks
Beginning direct3d gameprogramming02_overviewofhalandcom_20160408_jintaeks
 
Beginning direct3d gameprogramming01_thehistoryofdirect3dgraphics_20160407_ji...
Beginning direct3d gameprogramming01_thehistoryofdirect3dgraphics_20160407_ji...Beginning direct3d gameprogramming01_thehistoryofdirect3dgraphics_20160407_ji...
Beginning direct3d gameprogramming01_thehistoryofdirect3dgraphics_20160407_ji...
 
Beginning direct3d gameprogramming01_20161102_jintaeks
Beginning direct3d gameprogramming01_20161102_jintaeksBeginning direct3d gameprogramming01_20161102_jintaeks
Beginning direct3d gameprogramming01_20161102_jintaeks
 
Beginning direct3d gameprogramming03_programmingconventions_20160414_jintaeks
Beginning direct3d gameprogramming03_programmingconventions_20160414_jintaeksBeginning direct3d gameprogramming03_programmingconventions_20160414_jintaeks
Beginning direct3d gameprogramming03_programmingconventions_20160414_jintaeks
 
Beginning direct3d gameprogrammingmath06_transformations_20161019_jintaeks
Beginning direct3d gameprogrammingmath06_transformations_20161019_jintaeksBeginning direct3d gameprogrammingmath06_transformations_20161019_jintaeks
Beginning direct3d gameprogrammingmath06_transformations_20161019_jintaeks
 
Beginning direct3d gameprogrammingmath05_matrices_20160515_jintaeks
Beginning direct3d gameprogrammingmath05_matrices_20160515_jintaeksBeginning direct3d gameprogrammingmath05_matrices_20160515_jintaeks
Beginning direct3d gameprogrammingmath05_matrices_20160515_jintaeks
 
Beginning direct3d gameprogrammingmath04_calculus_20160324_jintaeks
Beginning direct3d gameprogrammingmath04_calculus_20160324_jintaeksBeginning direct3d gameprogrammingmath04_calculus_20160324_jintaeks
Beginning direct3d gameprogrammingmath04_calculus_20160324_jintaeks
 

Boost라이브러리의내부구조 20151111 서진택

  • 1. BoostBoost 라이브러리의 내부 구조라이브러리의 내부 구조 에 사용된 기법을 응용하기에 사용된 기법을 응용하기 KOG, 서진택 jintaeks@gmail.com 2015 년 11 월 11 일
  • 2. 발표자 , jintaeks@gmail.com  2000 년 ㈜ Kog 입사 – 프로그래머로 게임 개발 시작  ~2015 년 9 월 ㈜ Kog 프로그래머 – 프로그래머로 게임 개발 및 기술 지원 프로그래밍 – 참여 게임 • 와일드랠리 • 범퍼킹재퍼 • 엘소드 • 얼티밋레이스  저서 – 게임개발자를 위한 C++, 민프레스 , 2003 – MFC 의 구조와 원리 , 한빛미디어 , 2005 2
  • 3. 발표순서  base-from-member idiom  BOOST_FOREACH 의 내부 구조 – if-for combination idiom – RAII idiom – int-to-type idiom – BOOST_TYPEOF  boost::shared_ptr 의 내부 구조 – copy-and-swap idiom – safe-bool idiom  Q&A 3  이 발표는 boost 라이브러리에서 가장 많이 사용하는 BOOST_FOREACH() 와 shared_ptr 의 내부 구조를 분석합니다 .  그리고 바닥부터 해당 기능을 구현합니다 .  이 과정을 통해서 boost 가 사용한 기법들 을 프로그래밍에 응용하는 방법을 제시합 니다 .
  • 4. base-from-member: 문제 상황 class KObject { public: KObject() { m_iInitialized = 99; } int GetInitialized() const { return m_iInitialized; } private: int m_iInitialized; };//KObject 4 class KBase { public: KBase( KObject& obj_ ) { std::cout << obj_.GetInitialized() << std::endl; } };//class KBase  상속받은 클래스의 멤버를 베이스 클래스 가 접근하는 경우가 있습니다 .  KBase 의 생성자에서 m_object 의 멤버를 호출하는 것은 객체가 아직 초기화되지 않 았으므로 안전하지 않습니다 .
  • 5. base-from-member: 해결방법 struct KPrivateBase { KObject m_object; };//struct KPrivateBase class KDerived2 : protected KPrivateBase, public KBase { public: KDerived2() : KBase( m_object ) { } private: //KObject m_object; };//class KDerived 5  base-from-member idiom 은 문제를 해결하 기 위해 다중 상속에서 호출되는 클래스 생 성자의 순서를 이용합니다 .  boost 의 많은 곳에서는 , 베이스 클래스의 생성자에서 완전히 초기화된 객체를 접근 하기 위해 이 방법을 사용합니다 .
  • 7. 문제제기 : BOOST_FOREACH std::vector<int> vecInt; BOOST_FOREACH( int& a, vecInt ) { } 7  어떻게 매크로에 사용한 변수의 범위를 { 와 } 로 제한하는 것이 가능할까요 ?
  • 8. 관찰 : if 의 조건문에 사용한 변수 #include <iostream> #include <algorithm> #include <functional> #include <vector> #include <boost/foreach.hpp> #include <boost/typeof/typeof.hpp> void main() { if( int iBlockScope = 0 ) {} else { iBlockScope = 3; std::cout << iBlockScope << std::endl; } //std::cout << iBlockScope << std::endl; // invalid access }//main() 8  if 문에 선언된 변수는 if 블록의 하부에서 사용 할 수 있습니다 . 또한 if 블록을 빠져 나가면 접 근할 수 없습니다 .  즉 if 문에 선언된 변수의 범위 scope 는 if- 블록 안으로 제한됩니다 .  변수를 true 가 아닌 값으로 초기화하면 , else- 블록에서 접근하는 것이 가능합니다 .
  • 9. 관찰 : for 에 사용한 문장 #include <iostream> void main() { if( int iBlockScope = 0 ) {} else for( printf( "hello worldrn" ); iBlockScope == 0; iBlockScope = 1 ) { iBlockScope = 3; std::cout << iBlockScope << std::endl; } /** hello world 3 계속하려면 아무 키나 누르십시오 . . . */ }//main() 9  for 문의 첫번째 문장에는 조건에 상관없이 자유롭게 문장 statement 을 적을 수 있습 니다 . 또한 for 문에서 선언된 변수는 block scope 를 가집니다 .
  • 10. 관찰 : { 와 } 사용이 가능한 RAII 매크로 정의 #include <iostream> #define RAII( statement_ ) if( int iBlockScope = 0 ) {} else for( statement_; iBlockScope == 0; iBlockScope = 1 ) void main() { RAII( printf( "hello worldrn" ) ) { iBlockScope = 3; std::cout << iBlockScope << std::endl; }//RAII() /** hello world 3 계속하려면 아무 키나 누르십시오 . . . */ }//main() 10  RAII 는 초기화 initialize 코드와 마무리 finalize 코드가 자동으로 호출되도록 하 는 디자인 패턴입니다 . RAII 는 코드를 안 전하고 깔끔하게 만듭니다 .  if-for 문장을 조합하면 , 블록 scope 를 가지는 변수를 , { 안에서만 사용하도록 매크로를 정의할 수 있습니다 .
  • 11. int2type template <int I> struct Int2Type { enum { value = I }; }; template <class T, unsigned int N> class Array : public std::array <T, N> { enum AlgoType { NOOP, INSERTION_SORT, QUICK_SORT }; static const int algo = (N==0) ? NOOP : (N==1) ? NOOP : (N<50) ? INSERTION_SORT : QUICK_SORT; void sort (Int2Type<NOOP>) {} void sort (Int2Type<INSERTION_SORT>) {} void sort (Int2Type<QUICK_SORT>) {} public: void sort() { sort (Int2Type<algo>()); } 11 int main(void) { Array<int, 1> a; a.sort(); // No-op! Array<int, 400> b; b.sort(); // Quick sort }  컴파일 시간에 정수 상수를 타입 으로 취급하도록 합니다 .
  • 12. 관찰 : sizeof 에 표현식 사용 #include <iostream> #include <vector> #include <boost/typeof/typeof.hpp> #include <boost/mpl/int.hpp> template<class T> T type_encoder( T expression_ ) { return expression_; } template<int ID> struct typeid_wrapper { typedef typename extract_type<int_<ID> >::id2type id2type; typedef typename id2type::type type; }; 12  함수 템플릿은 파라미터로 전달 된 표현식의 타입을 자동으로 유추하는 역할로 사용할 수 있 습니다 .  id 로 구분되는 유일한 타입을 생성하고 , typeid_wrapper<>::type 으로 접근합니다 .
  • 13. 관찰 : BOOST_TYPEOF 의 원리 #include <iostream> #include <vector> #include <boost/typeof/typeof.hpp> #include <boost/mpl/int.hpp> … void main() { int i = 1; sizeof( type_encoder(i+3) ); typeid_wrapper<sizeof( type_encoder(i+3) ) >::type k; BOOST_TYPEOF( i + 3 ) j; j = 3; std::cout << i << std::endl; std::cout << j << std::endl; }//main() 13  sizeof() 에는 type 뿐만 아니라 unary expression 을 전달할 수 있습니다 .  함수 호출과 sizeof() 를 이용하면 표현식을 템플릿에 전달할 수 있습니다 .  이런 원리를 사용하여 구현된 , BOOST_TYPEOF() 는 표현식의 타입을 구합니다 ! i+3 의 타입이 int 이므로 int j; 와 같은 문장입니다 .
  • 14. 응용 예 : KLOCK_BEGIN KLOCK_DECLARE_INIT( KTest, m_int, (0) );   void main() { KLOCK_DECLARE( std::vector<int>, vecUserInfo ); std::cout << vecUserInfo.size() << std::endl;   //vecUserInfo.push_back( 3 ); // compile time error //m_int.SetInt( 5 ); // compile time error   KLOCK_BEGIN( m_int ) KLOCK_BEGIN( vecUserInfo ) { m_int.SetInt( 5 ); vecUserInfo.push_back( 5 ); } std::cout << m_int.GetInt() << std::endl; std::cout << vecUserInfo.size() << std::endl; }  14  특정한 멤버 변수를 읽는 것은 허용하 되 , 쓰는 동작은 에러가 나도록 할 수 있습니다 .  KLOCK_DECLARE() 로 선언한 변수는 이러한 특징을 가지도록 합니다 .  KLOCK_BEGIN() 으로 특정한 변수에 대한 쓰기 권한을 허용할 수 있습니다 .  이러한 기법은 읽기와 쓰기 동작을 구 분하는 코드를 작성하도록 합니다 .  변수를 변경할 때 실행되어야 하는 코 드를 지정함으로써 , 여러가지 housekeeping 동작을 숨길 수 있습니 다 .
  • 16. Step1: for- 문장 #include <iostream> #include <algorithm> #include <functional> #include <vector> #include <boost/foreach.hpp> void main() { std::vector<int> vecIntData; vecIntData.push_back( 1 ); vecIntData.push_back( 3 ); for( std::vector<int>::iterator vitor = vecIntData.begin(); vitor != vecIntData.end(); ++vitor ) { int& iData = *vitor; std::cout << iData << std::endl; }//for }//main() 16  for 문을 이용하여 vector 를 iteration 하는 코드를 작성했습니 다 .
  • 17. Step2: set_true() 정의하기 bool set_true( bool& bInOutVariable_ ) { bInOutVariable_ = true; return false; } void main() { std::vector<int> vecIntData; vecIntData.push_back( 1 ); vecIntData.push_back( 3 ); … 17  set_true() 는 항상 false 를 리턴합니 다 . 인자로 전달된 bool 변수를 true 로 만드는 역할을 합니다 .
  • 18. Step3: use BOOST_TYPEOF … //BOOST_FOREACH( int& iData, vecIntData ) if( bool bForBreaker = false ) {} else for( BOOST_TYPEOF(vecIntData)::iterator vitor = vecIntData.begin() ; bForBreaker == false && vitor != vecIntData.end() ; ++vitor ) { if( set_true(bForBreaker) ) {} else for( int& iData = *vitor; bForBreaker == true; bForBreaker = false ) { std::cout << iData << std::endl; //break; }//for }//for }//main() 18  set_true() 는 변수를 항상 true 로 설정하지만 , false 를 리턴하므로 , 변수값을 변경하는 일만 합 니다 .  set_true() 가 필요한 이유는 최종적으로 정의한 매 크로 안에서 break 를 사용했을 때 , break 문장이 바깥 for- 문장을 빠져나가도록 하기 위함입니다 .
  • 19. Step4: { 를 제거하기 void main() { std::vector<int> vecIntData; vecIntData.push_back( 1 ); vecIntData.push_back( 3 ); //BOOST_FOREACH( int& iData, vecIntData ) if( bool bForBreaker = false ) {} else for( BOOST_TYPEOF(vecIntData)::iterator vitor = vecIntData.begin() ; bForBreaker == false && vitor != vecIntData.end() ; ++vitor ) if( set_true(bForBreaker) ) {} else for( int& iData = *vitor; bForBreaker == true; bForBreaker = false ) std::cout << iData << std::endl; }//main() 19  BOOST_TYPEOF() 를 사용하여 매크 로로 전달된 표현식의 iterator 를 접근 합니다 .  RAII 구현을 위해서 { 와 } 는 포함되 지 않게 매크로 작성을 준비합니다 .
  • 20. FOREACH 완성 #define FOREACH( statement_, container_ ) if( bool bForBreaker = false ) {} else for( BOOST_TYPEOF(container_)::iterator vitor = container_.begin() ; bForBreaker == false && vitor != container_.end() ; ++vitor ) if( set_true(bForBreaker) ) {} else for( statement_ = *vitor; bForBreaker == true; bForBreaker = false ) void main() { std::vector<int> vecIntData; vecIntData.push_back( 1 ); vecIntData.push_back( 3 ); FOREACH( int& iData, vecIntData ) { std::cout << iData << std::endl; //break; }//FOREACH() }//main() 20  중첩된 FOREACH() 와 배열을 지원하기 위해서는 추가적인 처리가 필요합니다 .
  • 21. 응용 예 : ASSET_FOREACH  기본적으로 구현한 FOREACH() 를 응용하여 , 프로그 램의 내부 로직에 의존적인 여러가지 매크로를 정의 할 수 있습니다 . – 프로그램에서 현재 관리중인 모든 asset 들에 대한 커스텀 iteration 을 작성할 수 있습니다 . – .xml 파일을 로드하고 나서 , 모든 element 에 대한 커스텀 iteration 을 작성할 수 있습니다 . – 프로그램에서 현재 생성된 모든 게임 객체에 대한 커스텀 iteration 을 작성할 수 있습니다 . 21
  • 23. void 참조를 특화로 구현 23 template<class T> struct shared_ptr_traits { typedef T& reference; }; template<> struct shared_ptr_traits<void> { typedef void reference; };  void 타입에 대한 reference 가 가능하도록 템플릿 특화 specialization 을 사용하여 미 리 구현해 둡니다 .  기타 type-trait 에 대한 설명은 생략합니다 .
  • 24. shared_ptr: 생성자 구현 24 template<class T> class shared_ptr { public: typedef shared_ptr<T> this_type; typedef T value_type; typedef T* pointer; typedef typename shared_ptr_traits<T>::reference reference; public: shared_ptr(T * p = 0) : px(p), pn(0) { if( px != NULL ) pn = new int(1); }  생성자에서는 전달받은 raw pointer 를 초 기화합니다 .  참조 카운팅을 위한 메모리 할당을 하고 , 참조 카운터를 1 로 초기화합니다 .
  • 25. shared_ptr: 복사 생성자와 파괴자 구현 25 shared_ptr( const shared_ptr& right_ ) : px( 0 ), pn( 0 ) { release(); px = right_.px; pn = right_.pn; if( px != NULL ) *pn += 1; } ~shared_ptr() { release(); }  복사 생성자는 먼저 이전에 할당되어 있는 리소스를 해제 합니다 .  새로운 리소스에 대한 참조를 설정하고 , 참조 카운터를 증가시킵니다 .
  • 26. shared_ptr: operator=(), operator pointer() 26 shared_ptr& operator=( const shared_ptr& right_ ) { release(); px = right_.px; pn = right_.pn; if( px != NULL ) *pn += 1; return *this; } operator pointer() const { return px; }  대입 연산자는 복사 생성자와 거의 동일하 게 구현합니다 .  타입에 대한 포인터 연산이 제대로 동작하 도록 operator T*() 를 정의합니다 .
  • 27. shared_ptr: release() 구현 27 void release() { if( px != NULL && *pn >= 1 ) { *pn -= 1; if( *pn == 0 ) { delete px; px = NULL; delete pn; pn = NULL; }//if }//if px = NULL; pn = NULL; }  release() 는 먼저 참조 카운터를 감소합니 다 .  참조 카운터가 0 이되면 , 실제 리소스를 해제 합니다 .
  • 28. shared_ptr: reset(), use_count() 구현 28 void reset() { release(); } void reset(T * p) { release(); px = p; pn = NULL; if( px != NULL ) pn = new int(1); } int use_count() const { return *pn; }  reset() 은 해제 후 할당과 동일합니다 .  완성된 shared_ptr 은 암시적 생성 implicit construction 을 지원하지 않으므로 , reset() 구현이 반드시 필요합니다 .  use_count() 는 현재 참조 카운터를 리턴합 니다 .
  • 29. shared_ptr: operator*(), operator->() 구현 29 reference operator*() const // never throws { return *px; } T* operator->() const // never throws { return px; } private: T* px; int* pn; };//template<class T> class shared_ptr  간접지정 연산자와 화살표 연산자가 제대 로 동작하도록 함수를 작성합니다 .  void* 에 대한 참조가 동작하도록 하기 위해 서는 void 에 대한 참조를 템플릿 특화로 미 리 구현해 두어야 합니다 .
  • 30. main() 에서 테스트 30 int main() { typedef shared_ptr<int> IntPtr; IntPtr spInt = new int(3); // spInt.use_count() == 1 if( spInt != NULL ) { std::cout << *spInt << std::endl; // 3 }//if IntPtr spInt2 = spInt; // spInt.use_count() == 2 IntPtr spInt3 = spInt; // spInt.use_count() == 3 spInt.reset( new int(4) ); // spInt.use_count() == 1 *spInt = 5; // 3 changed to 5 if( spInt2 != NULL ) // spInt2.use_count() == 2 { std::cout << *spInt2 << std::endl; // 3 }//if return 0; }//int main()
  • 31. copy-and-swap: swap() 메서드 구현 31 void swap( shared_ptr<T>& right_ ) // never throws { std::swap( px, right_.px ); std::swap( pn, right_.pn ); }  exception safety 1) Basic: component 의 invariant 는 보존되고 , resource leak 은 발생하지 않아야 합니다 . 2) Strong: 성공적으로 완료되었던지 예외를 던졌던 지 둘 중의 하나여야 합니다 . 3) No-throw: 예외를 던지지 않아야 합니다 .  copy-and-swap 을 지원하기 위해서 shared_ptr 의 swap() 은 예외를 던지지 않도록 구현해야 합니다 .
  • 32. shared_ptr: swap() 을 반영한 수정 32 shared_ptr& operator=( const shared_ptr& right_ ) { //release(); //px = right_.px; //pn = right_.pn; //if( px != NULL ) // *pn += 1; this_type(right_).swap(*this); return *this; } void reset(T * p) { //release(); //px = p; //pn = NULL; //if( px != NULL ) // pn = new int(1); this_type(p).swap(*this); }
  • 33. 관찰 : if 의 조건문 표현식 33 class KBoolTest { public: operator bool() const { return true; } operator int() const { return 1; } operator int*() const { return NULL; } int GetValue() const { return 9; } }; int main() { KBoolTest t; if( t ) std::cout << t.GetValue() << std::endl; return 0; }//int main()  if 문의 조건은 일반적인 bool 표현식이 아닌 C 가 허용하는 참인 조건식을 적을 수 있습니다 .  평가의 partial order 의 순서는 bool  native type  pointer 의 순입니다 .
  • 34. safe bool idiom 34 //int* p = spInt; // (1) //if( spInt < spInt ) // (2) //{ //}  지금까지의 구현은 (1) 과 (2) 처럼 잘못된 사 용이나 , 의미없는 bool 표현식을 막지 못 합니다 .   template <typename T> void some_func(const T& t) {     if (t)          t->print();   }  smart pointer T 에 대해 이 문장이 동작 하려면 T 는 bool 형에 대한 형 변환 연 산자를 제공해야 합니다 .
  • 35. 해결시도 1: operator bool() 구현 35 class Testable {     bool ok_;   public:     explicit Testable(bool b=true):ok_(b) {}       operator bool() const {       return ok_;     }   };  shared_ptr 은 자신이 valid 한 raw pointer 를 가질 때 , true 를 리턴하는 operator bool() 을 작성할 수 있습니다 .
  • 36. operator bool() cont. 36 test << 1; // (1)   int i=test; // (2)   Testable a;   AnotherTestable b;     if (a==b) { // (3)   }     if (a<b) { // (4)   }  이 구현은 (1), (2) 같은 의미 없는 문장 이나 , (3), (4) 같은 의미 없는 bool 검 사를 막지 못합니다 .
  • 37. 해결시도 2: operator void*() 구현 37  operator void*() const {     return ok_==true ? this : 0;   }  이 구현은 영리해 보이지만 , 아래의 문장처럼 delete 를 직접호출 할 수 있는 약점을 가집니다 . Testable test; delete test;
  • 38. 해결시도 3: nested class 38 class Testable {     bool ok_;   public:     explicit Testable(bool b=true):ok_(b) {}       class nested_class;       operator const nested_class*() const {       return ok_ ? reinterpret_cast<const nested_class*>(this) : 0;     }   }; Testable b1,b2;     if (b1==b2) {   }     if (b1<b2) {   }  safe bool 을 위한 nested class 구현 역시 의미없는 bool 검 사를 막지 못합니다 .  이 문제를 해결하려면 포인터 형변환이 되지만 , < 같은 비교 연산자를 지원하지 않는 데이터 타입을 사용하는 것입니다 .  흥미롭게도 멤버 함수에 대한 포인터가 그렇게 동작합 니다 !
  • 39. 최종 버전 : safe bool idiom 39 class Testable {     bool ok_;     typedef void (Testable::*bool_type)() const;     void this_type_does_not_support_comparisons() const {}   public:     explicit Testable(bool b=true):ok_(b) {}       operator bool_type() const {       return ok_==true ?         &Testable::this_type_does_not_support_comparisons : 0;     }   };  if- 문장의 조건 표현식에 포인터가 사용될 수 있는 점을 이용하여 , 함수 포인터를 리턴하 는 연산자 함수를 정의합니다 .
  • 40. shared_ptr 의 내부 : unspecified_bool_type 사용 40 //operator pointer() const //{ // return px; //} void unspecified_bool() const { } typedef void (shared_ptr::*unspecified_bool_type)() const; operator unspecified_bool_type() const // never throws { return px == 0 ? 0 : &shared_ptr::unspecified_bool; }  boost 의 실제 코드는 unspecified_bool_type() 을 사용합니다 .  C++ 표준 라이브러리 뿐만 아니라 , 게임 엔진의 스마트 포인터 구현은 모두 이러한 기법을 사용합니다 .
  • 41. shared_ptr 에 적용된 safe bool idiom 41 typedef shared_ptr<int> IntPtr; IntPtr spInt = new int(3); IntPtr spInt2 = spInt; IntPtr spInt3 = spInt; spInt.reset( new int(4) ); *spInt = 5; if( spInt2 != NULL ) { std::cout << *spInt << std::endl; }//if int* p = spInt; // (1) error if( spInt2 < spInt3 ) // (2) error { }  이제 (1) 과 (2) 같은 의미 없는 문 장은 컴파일 시간 에러가 발생합 니다 .
  • 42. implicit constructor 문제 해결하기 42 void Test( shared_ptr<int> spInt_ ) { } int iData = 5; Test( &iData );  실제 포인터가 아닌 , 포인터 표현식에 대한 shared_ptr 생성을 막을 필요가 있습니다 .  이 문제에 대한 해결방법은 명시적 생성만 가능하도록 클래스를 설계하는 것입니다 . explicit shared_ptr(T * p = 0) : px(p), pn(0) { if( px != NULL ) pn = new int(1); }
  • 44. weak_ptr<T> 44 #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> class Test; typedef boost::shared_ptr<Test> TestPtr; typedef boost::weak_ptr<Test> TestWeakPtr; class Test { public:  shared_ptr 을 제공할 때 , 포인터 순환 참 조 문제등을 해결하기 위해서 weak_ptr 을 함께 제공합니다 .
  • 45. weak_ptr<T> cont. 45 class TestRef { public: TestRef(){} void SetTest( TestPtr tp ) { m_tp = tp; } void Print() const { if( TestPtr tp = m_tp.lock() ) { tp->Print(); } } private: TestWeakPtr m_tp; };  weak_ptr 을 사용하는 경우 , 지금 사용해 도 안전한 실제 포인터를 얻기 위해서 lock() 을 호출합니다 . int main() { TestPtr tp = Test::CreateTest( 1 ); TestRef ref; ref.SetTest( tp ); tp.reset(); ref.Print(); }//int main()
  • 46. weak_ptr<T> lock() 46  weak_ptr<T> 의 lock() 구현 shared_ptr<T, A, D> lock() const // never throws { // optimization: avoid throw overhead if(expired()){ return shared_ptr<element_type, A, D>(); } BOOST_TRY{ return shared_ptr<element_type, A, D>(*this); } }  shared_ptr<T>( weak_ptr<Y> ) 구현 template<class Y> explicit shared_ptr(weak_ptr<Y> const & r): pn(r.pn) // may throw { // it is now safe to copy r.px, as pn(r.pn) did not throw px = r.px; }
  • 47. raw pointer 에서 shared_ptr 얻기 : factory 47 class X { private: X() { ... } public: static shared_ptr<X> create() { shared_ptr<X> px(new X); // use px as 'this_' return px; } };  shared_ptr<T> 로 관리되지 않는 raw 포 인터에서 shared_ptr<T> 을 얻을 필요가 있습니다 .  클래스 객체가 shared_ptr<T> 로 관리되 더라도 , 생성자에서 shared_ptr<T> 를 얻 을 방법도 없습니다 .  해결 방법은 weak_ptr 과 팩토리 함수를 사용하는 것입니다 .
  • 48. factory: this 에 대한 shared_ptr<T> 48 class impl: public X, public Y { private: weak_ptr<impl> weak_this; impl(impl const &); impl & operator=(impl const &); impl() { ... } public: static shared_ptr<impl> create() { shared_ptr<impl> pi(new impl); pi->weak_this = pi; // (1) 팩토리에서 weak_ptr<T> 을 초기화 해 놓습니다 . return pi; } virtual void f() { ... } virtual shared_ptr<X> getX() { shared_ptr<X> px(weak_this); return px; } };  대상 객체를 생성할 때 , weak_ptr 이 적절 하게 초기화되도록 합니다 .  그러면 , 후에 필요하면 대상 객체에 대한 shared_ptr 을 얻을 수 있습니다 .
  • 49. boost::enable_shared_from_this<T> 49 #include <iostream> #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> class Test; typedef boost::shared_ptr<Test> TestPtr; class Test : public boost::enable_shared_from_this<Test> { public: static TestPtr CreateTest(int i) { TestPtr sp( new Test( i ) ); return sp; } Test(int i) : m_i(i) {} void Print() const { std::cout << m_i << std::endl; } private: int m_i; };  이 역할을 하는 boost 의 베이스 클래스가 enabled_shared_from_this 입니다 .
  • 50. shared_from_this() 50 void TestFun( Test* pt ) { TestPtr tp; if( pt != NULL ) tp = pt->shared_from_this(); if( tp != NULL ) { tp->Print(); } }  Test 가 enable_shared_from_this 를 상속받은 경ㅇ 우 , raw pointer 에서 shared_ptr 을 얻기 위해서는 shared_from_this() 를 호출합니다 .
  • 51. 응용 예 : RAII 51 #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> #include <boost/typeof/typeof.hpp> #define KSmartPointer(type_) class type_; typedef boost::shared_ptr<type_> type_##SharedPtr; typedef boost::weak_ptr<type_> type_##WeakPtr; #define IF_MEMBER_WEAKPTR( member_name_ ) if( boost::shared_ptr<BOOST_TYPEOF(member_name_)::element_type> member_name_ = this- >member_name_.lock() )  게임 객체가 관리되는 리소스가 있는 경우에만 사용하려 고 하는 경우 , 리소스에 대한 weak_ptr 을 멤버로 가집니 다 .  게임 객체가 실제 객체를 사용하려고 하면 , lock() 호출이 필요합니다 .  이러한 패턴을 RAII 매크로로 작성했습니다 .
  • 52. 응용 예 cont. 52 class TestContainer { public: TestContainer(){} void SetTest( TestSharedPtr tp ) { m_tp = tp; } void Print() const { IF_MEMBER_WEAKPTR( m_tp ) { m_tp->Print(); }//if } private: TestWeakPtr m_tp; };  IF_MEMBER_WEAKPTR() 은 RAII 스타일의 매크 로로 멤버에 대한 안전한 접근을 보장합니다 .

Hinweis der Redaktion

  1. BOOST_TYPEOF()를 사용하면, 매크로 인자만 사용하여 해당하는 iterator타입을 접근하는 코드를 작성하는 것이 가능합니다.