RAII (Resource Acquisition Is Initialization)

디클

·

2008. 5. 1. 01:36

Resource Acquisition Is Initialization #

직역하면 자원의 획득은 초기화이다 ..

이말은 C++계의 대부 Bjarne Stroustrup 에 의해 나온 관용구 입니다.
http://www.research.att.com/~bs/homepage.html

자원(여기서 자원이란 메모리 뿐만 아니라 OS에 요청에서 얻어지는 모든건 ..)의
소멸(해제)은 Destructor(소멸자)에서 처리 하라는 말과 일맥 상통하는 말입니다.

자원의 획득은 생성자에서, 그 자원의 소멸은 소멸자에서 처리하여 어떠한 경우에도
자원의 leak이 발생하지 않게 처리하자 란 생각입니다.

만약 다음과 같은 코드가 쓰레드의 함수안에서 실행 되고 있을때 ...
CRITICAL_SECTION g_cs;
UINT Run(LPVOID)
{
  if (조건) {
    EnterCriticalSection(&g_cs); // 임계영역에 들어갑니다. 
    AFunction();
    BFunction();
    LeaveCriticalSection(&g_cs); // 임계영역에서 나옵니다. 
  }
  else {
    // 다른 작업 
  }
  return 0;
}
AFunction 함수에서 예외가 발생하여 Run함수를 빠져 나간다면 g_cs의 내용은
임계영역에서 못빠져 나온채 남아 있게 된니다.
그럼 나머지 쓰레드에서 실행되던 코드들은 EnterCriticalSection(&g_cs);
코드 앞에서 모두 대기하는 상태가 되어 프로그램이 DeadLock 상태에 빠지게 됩니다.

그러나 아래의 코드는 ...
class CriticalSection
{
public:
  CriticalSection(CRITICAL_SECTION *pcs) : pcs_(pcs)
  {
    EnterCriticalSection(pcs_);
  }

  ~CriticalSection()
  {
    LeaveCriticalSection(pcs_);
  };

private:
  CRITICAL_SECTION *pcs_;
};

CRITICAL_SECTION g_cs;
UINT Run(LPVOID)
{
  if (조건) {
    // 임계영역에 들어갑니다. 
        // 그리고 cs의 변수 생명이 끝날때 (if 문이 끝날때) 
        // 소멸자가 호출되 임계영역의 자원을 해제 해줍니다. 
    CriticalSection cs(&g_cs);

    AFunction();
    bool b = BFunction();
        if (!b) {
          return -1;
        }
  }
  else {
    다른 작업
  }
  return 0;
}

AFunction혹은 BFunction에서 예외가 발생하던 중간의 return문을
만나서 쓰레드 함수를 탈출한다고 해도 CriticalSection의 소멸자에서
임계영역의 자원을 풀어주므로 보다 안전한 코드를 만들수가 있습니다.

이개념이 RAII(Resource Acquisition Is Initialization) 입니다.

이 RAII 철학을 바탕으로 만들어진 C++ 표준 객체가 std::auto_ptr 입니다.
std::auto_ptr은 생성자에서 할당된 포인터를 받아 소멸자에서
delete 시키는 기능을 가진 포인터타입의 래퍼 객체 입니다.

std::auto_ptr은 다소 익숙하지 않은(일반포인터와 비교해)
소유정책을 가지고 있지만 호환성있는 표준 객체라는 점에서
눈여겨볼 아니 필요할때 꼭 사용되어져야 될 객체 입니다.

#include <iostream>
#include <memory>

void f()
{
  // string 객체를 동적으로 생성하고 명시적인 해제가 없지만 
  // std::auto_ptr의 소멸자에서 string 객체에 대한 할당된 포인터 객체를 
  // delete 해줄 것입니다. 
  std::auto_ptr<string> p(new string("메롱"));

  std::cout << *p << std::endl; // 포인터와 같은 인터페이스를 가집니다. 
  std::cout << p->lenght() << std::endl;
}

int main()
{
        f();
}


이밖에 RAII의 기본철학을 이용한 COW(copy on write)기법이나
Reference Counting 기법을 이용한 smart포인터등 보다 안전하고
융통성있는 객체의 코드를 만들수 있을 것입니다.


MS의 COM은 Reference Counting을 이용한 스마트 포인터로 핸들링 되며
_bstr_t 객체는 COW 타입을 사용해 성능 향상을 꾀한 예로 들수 있을 것입니다.

이밖에도 boost(표준라이브러리는 아니지만 앞으로 표준화의 가능성이 높은 성능좋은
라이브러리)의 smart_ptr 객체들도 auto_ptr의 확장 개념으로서 제공되고 있습니다.


'Dev > C++' 카테고리의 다른 글

qsort vs sort  (0) 2008.05.01
최소 완전한 클래스를 만들어라  (0) 2008.05.01
RAII (Resource Acquisition Is Initialization)  (1) 2008.05.01
상속되지 않는것  (0) 2008.05.01
STL  (0) 2008.05.01
new 2  (0) 2008.05.01

1개의 댓글