다른 말로 SBRM ( Scope-Bound Resource Management )라고도 부르는 이 개념은 「일종의 디자인 패턴」으로
"자원 획득은 초기화다"라고 직역할 수 있는 말은 '메모리 할당의 과정을 객체 초기화 과정과 함께해라' 라고 할 수 있겠다.
C++ programming technique which binds the life cycle of a resource that must be acquired before use to the lifetime of an object. [1]
" 사용하기 전에 획득해야 하는 리소스의 수명 주기를 개체의 수명에 바인딩하는 C++ 프로그래밍 기법. " 이라는 말처럼 기능이 아닌 기법이기 때문에 이렇게 작동될 수 있는 원리를 알아야 한다고 생각한다.
C++에서 리소스는 동적 메모리를 포함해 다양한 것을 뜻한다. 무엇을 리소스라 부르던 사용하기 위해선 먼저 할당해줘야 하고 사용한 후에는 할당된 메모리를 해제해줘야 한다. 이 일련의 과정을 「 리소스의 수명주기 」 라 부른다.
이 작업이 실행되지 않으면
등의 에러가 발생하는데 이는 프로그램 실행 상에 크고 작은 문제를 발생시킨다.
new / malloc 과 delete / free 등의 키워드를 잘 사용하면 해결되는 문제지만 프로그램의 크기가 커지면 프로그래머의 손으로 직접 모든 코드의 메모리 생성, 해제 부분을 관리하기란 쉽지 않다. 때문에 다른 언어에서는 Garbage Collection 등의 자원관리를 돕는 기능이 포함되어 있다.
이런 기능이 없는 C++은 프로그래머의 실력에 따라 문제의 발생 여부가 발생된다.
C++의 객체는 Lifetime 이라는 런타임(Runtime) 특성을 가지는데 이는 "프로그램 실행 중 생성되는 시점과 삭제되는 시점이 존재한다."는 뜻이다.
메모리 영역 상 Stack에 저장되는 로컬 변수들이 함수의 시작에 생성되고 끝에 삭제될 수 있는 이유는 로컬변수의 특징이라 알고 있었지만 '객체의 수명'이라는 특징으로 묶여 컴파일러와 C++ 런타임에 의해 자동으로 관리되고 있던 것이다.
수명 주기 + 수명이란 말을 썻는데 풀어쓰자면,
"자원 관리용 클래스를 만들어 리소스가 필요해져 할당되어야 하는 상황에서 생성자에서 할당을, 소멸자에서 해제를 동작하게 하자."
로 객체의 시작과 끝을 컴퓨터가 정해주는 특징을 이용해 생성자에서 할당 동작을, 소멸자에서 해제 동작을 실행하면 자원 관리의 문제를 컴퓨터에게 넘길 수 있다는 표현이다.
자원의 수명 주기와 객체의 수명 주기의 결합으로 자원의 관리 책임을 객체에 넘겨 런타임이 자동으로 관리하게 만드는 것이다. 소멸자는 예외가 발생해도 항상 실행되기 때문에 메모리 누수도 발생하지 않는다.
class widget
{
private:
int* data;
public:
widget(const int size) { data = new int[size]; } // 할당
~widget() { delete[] data; } // 해제
void do_something() {}
};
void functionUsingWidget()
{
widget w(1000000); // 범위에 바인딩된 객체 생애
// 멤버 변수 w.data가 포함된 W 생성
w.do_something();
} // w와 w.data가 자동으로 삭제와 해제가 이루어진다.
1. RAII라 거창하게 말해도 프로그래밍 '기법'이기 때문에 비슷한 기능을 하더라도 생성 삭제 전용 멤버 함수를 따로 작성하는 등, 생성자/소멸자에서 메모리 관리 동작이 실행되지 않으면 RAII 기법이 적용된 클래스라 부르지 않는다.
2. RAII가 적용된 대표적인 클래스로 스마트 포인터와 std::lock_guard 등이 존재한다.
[1] : cppreference.com
[2] : MSLearn : RAII
Pragma 키워드 (1) | 2023.11.01 |
---|---|
Extern 키워드 (0) | 2023.11.01 |
Inline 키워드 (1) | 2023.10.12 |
Static 키워드 (1) | 2023.10.12 |
메모리 구조 (0) | 2022.12.28 |