C++에서의 RAII란?
RAII(Resource Acquisition Is Initialization, 자원 획득은 곧 초기화)는 C++에서 자원의 생명 주기를 객체의 생명 주기에 연결해 관리하는 핵심 프로그래밍 기법입니다. 이 기법은 클래스 기반으로 구현되며, 자원의 획득과 해제를 컴파일러가 자동으로 처리하도록 만들어 줍니다.
RAII는 여러 자원을 하나의 클래스로 캡슐화합니다. 객체가 생성될 때 생성자가 자원 할당을 담당하고, 객체가 소멸될 때 소멸자가 자원 해제를 수행합니다.
이 덕분에 예외가 발생하거나 함수가 중간에 반환되더라도 스택 되감기(stack unwinding) 과정에서 소멸자가 반드시 호출되므로 자원 누수(resource leak)를 방지할 수 있습니다. 즉, 객체가 살아 있는 동안에는 해당 자원이 반드시 유지된다는 보장을 받게 됩니다.
RAII 활용 예제
void file_write() {
static mutex m; // 파일 접근을 보호하는 뮤텍스
lock_guard<mutex> lock(m); // 파일 접근 전 뮤텍스 잠금
ofstream file("a.txt");
if (!file.is_open()) { // 파일이 열리지 않은 경우
throw runtime_error("unable to open file");
}
// 파일에 텍스트 쓰기
file << text << std::endl;
}위 예제에서 lock_guard가 대표적인 RAII 활용 사례입니다. 함수가 어떤 경로로 종료되더라도 lock_guard 객체의 소멸자가 호출되어 뮤텍스가 자동으로 해제되므로, 데드락 위험 없이 안전하게 동기화할 수 있습니다.
C++ 스마트 포인터란?
스마트 포인터(Smart Pointer)는 일반 포인터를 추상화한 데이터 타입으로, 파일 처리나 네트워크 소켓 같은 자원을 메모리처럼 관리할 수 있게 해줍니다. 자동 소멸, 참조 카운팅 등 다양한 기능을 제공하여 수동 메모리 관리로 인한 실수를 크게 줄여줍니다.
C++에서 스마트 포인터는 템플릿 클래스로 구현되며, 역참조 연산자(*)와 화살표 연산자(->)를 오버로딩하여 일반 포인터처럼 사용할 수 있습니다. 대표적인 스마트 포인터로는 auto_ptr, shared_ptr, unique_ptr, weak_ptr이 있으며, 참고로 auto_ptr은 C++11부터 폐기(deprecated)되었고 C++17에서 완전히 제거되었으므로 현재는 unique_ptr 사용이 권장됩니다.
스마트 포인터 구현 예제
#include <iostream>
using namespace std;
// 범용 스마트 포인터 클래스
template <class T>
class Smartpointer {
T *p; // 실제 포인터
public:
// 생성자
Smartpointer(T *ptr = NULL) {
p = ptr;
}
// 소멸자
~Smartpointer() {
delete(p);
}
// 역참조 연산자 오버로딩
T & operator * () {
return *p;
}
// 화살표 연산자 오버로딩 (T의 멤버를 포인터처럼 접근 가능)
T * operator -> () {
return p;
}
};
int main() {
Smartpointer<int> p(new int());
*p = 26;
cout << "Value is: " << *p;
return 0;
}실행 결과
Value is: 26
이 예제에서 Smartpointer 객체는 main 함수가 끝날 때 자동으로 소멸되며, 소멸자가 내부적으로 delete를 호출해 동적 메모리를 해제합니다. 이처럼 스마트 포인터를 사용하면 delete 호출을 잊어 발생하는 메모리 누수를 원천적으로 방지할 수 있습니다.