RAII란 뭘까요? Research Assistant 2형?

Resource Acquisition is initialization, "자원 획득은 초기화다"의 두문자어(acronym)입니다.

이게 뭔소리일까요; 알아봅시다

 

 

RAII (Resource Acquisition is Initialization)

RAII는 오브젝트의 생명주기에 관련된 내용입니다. C++에서 스택 메모리에 있는 변수들은 스코프를 빠져나오게 되면 소멸자 호출을 통해 stack unwinding이 진행됩니다. Exception이 던져지더라도 소멸자 호출은 보장됩니다.

따라서 Exception-safe 코드를 만들 때 꼭 필요한 개념입니다.

 

#include <fstream>
#include <iostream>
#include <mutex>
#include <stdexcept>
#include <string>

void WriteToFile(const std::string& message) {
  static std::mutex mutex;

  std::lock_guard<std::mutex> lock(mutex);

  std::ofstream file("example.txt");
  if (!file.is_open()) {
    throw std::runtime_error("unable to open file");
  }

  file << message << std::endl;

  // |file| will be closed first when leaving scope (regardless of exception)
  // mutex will be unlocked second (from lock destructor) when leaving scope
  // (regardless of exception).
}

위키에 있는 예제입니다. std::lock_guard가 RAII를 이용한 좋은 예시입니다. mutex에 락을 했는데 예외가 던져지면 락이 풀리지 않아 데드락이 발생합니다. lock_guard를 사용하면 소멸자에서 락을 푸니 exception-safe하게 됩니다.

fstream도 동일합니다. open 후 예외가 던져지면 소멸자에서 close 해버립니다.

 

 

주의사항

RAII는 스택에 할당된 객체에만 적용됩니다.

std::string firstLineOf(const char* filename){
    OpenFile f("boo.txt"); //stack allocated
    return f.readLine();
    //File closed here. `f` goes out of scope and destructor is run.
}

std::string firstLineOf(const char* filename){
    OpenFile* f = new OpenFile("boo.txt"); //heap allocated
    return f->readLine();
    //DANGER WILL ROBINSON! Destructor is never run, because `f` is never
    //deleted
}

힙에 동적할당된 객체에는 적용되지 않습니다. 이럴때는 스마트 포인터를 써야 좋겠죠

 

또한 예외가 어딘가에서 catch 되었을 때만 stack unwinding이 보장됩니다.

 

 

참고자료

반응형