Namespaces
Variants

RAII

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

자원 획득이 초기화다 또는 RAII는 C++ 프로그래밍 기법 [1] [2] 으로, 사용 전에 반드시 획득해야 하는 자원(할당된 힙 메모리, 실행 스레드, 열린 소켓, 열린 파일, 잠긴 뮤텍스, 디스크 공간, 데이터베이스 연결—제한된 공급량이 존재하는 모든 것)의 수명 주기를 객체의 수명 에 바인딩합니다.

RAII는 리소스가 객체에 접근할 수 있는 모든 함수에서 사용 가능하도록 보장합니다(리소스 가용성은 클래스 불변식 으로, 런타임 중복 검사를 제거합니다). 또한 모든 리소스가 해당 제어 객체의 수명이 종료될 때 획득 순서의 역순으로 해제됨을 보장합니다. 마찬가지로, 리소스 획득이 실패할 경우(생성자가 예외와 함께 종료될 때), 완전히 생성된 모든 멤버 및 기반 하위 객체가 획득한 모든 리소스는 초기화 순서의 역순으로 해제됩니다. 이는 핵심 언어 기능( 객체 수명 , 범위 종료 , 초기화 순서 스택 풀기 )을 활용하여 리소스 누수를 제거하고 예외 안전성을 보장합니다. 이 기법의 다른 이름은 범위-바인딩 리소스 관리 (SBRM)으로, RAII 객체의 수명이 범위 종료로 인해 끝나는 기본 사용 사례에서 비롯되었습니다.

RAII는 다음과 같이 요약할 수 있습니다:

  • 각 리소스를 클래스로 캡슐화합니다, 여기서
  • 생성자는 리소스를 획득하고 모든 클래스 불변 조건을 설정하거나, 이를 수행할 수 없는 경우 예외를 발생시킵니다,
  • 소멸자는 리소스를 해제하고 절대 예외를 발생시키지 않습니다;
  • 항상 RAII-클래스의 인스턴스를 통해 리소스를 사용하십시오. 해당 클래스는 다음 중 하나를 수행합니다
  • 자동 저장 기간 또는 임시 수명 자체를 가지거나,
  • 자동 또는 임시 객체의 수명에 의해 제한되는 수명을 가집니다.

이동 의미론은 컨테이너 내부 및 외부 객체 간, 그리고 스레드 간에 자원과 소유권의 이전을 가능하게 하면서도 자원 안전성을 보장합니다.

(since C++11)

open() / close() , lock() / unlock() , 또는 init() / copyFrom() / destroy() 멤버 함수를 가진 클래스들은 RAII가 아닌 클래스의 전형적인 예시입니다:

std::mutex m;
void bad() 
{
    m.lock();             // 뮤텍스 획득
    f();                  // f()가 예외를 발생시키면 뮤텍스가 절대 해제되지 않음
    if (!everything_ok())
        return;           // 조기 반환, 뮤텍스가 절대 해제되지 않음
    m.unlock();           // bad()가 이 문장에 도달하면 뮤텍스가 해제됨
}
void good()
{
    std::lock_guard<std::mutex> lk(m); // RAII 클래스: 뮤텍스 획득이 초기화임
    f();                               // f()가 예외를 발생시키면 뮤텍스가 해제됨
    if (!everything_ok())
        return;                        // 조기 반환, 뮤텍스가 해제됨
}                                      // good()이 정상적으로 반환되면 뮤텍스가 해제됨

표준 라이브러리

C++ 라이브러리 클래스 중 자체 리소스를 관리하는 클래스들은 RAII를 따릅니다: std::string , std::vector , std::jthread (C++20부터) 그리고 많은 다른 클래스들은 생성자에서 리소스를 획득하고(오류 발생 시 예외를 던짐), 소멸자에서 이를 해제하며(절대 예외를 던지지 않음), 명시적인 정리가 필요하지 않습니다.

또한 표준 라이브러리는 사용자 제공 리소스를 관리하기 위한 여러 RAII 래퍼를 제공합니다:

(C++11부터)

참고 사항

RAII는 사용 전에 획득되지 않는 자원의 관리에는 적용되지 않습니다: CPU 시간, 코어 가용성, 캐시 용량, 엔트로피 풀 용량, 네트워크 대역폭, 전력 소비, 스택 메모리. 이러한 자원들에 대해서는 C++ 클래스 생성자가 객체 수명 동안 자원 가용성을 보장할 수 없으며, 다른 자원 관리 수단을 사용해야 합니다.

외부 링크

  1. Stroustrup의 C++ FAQ에서의 RAII
  2. C++ 핵심 가이드라인 E.6 "RAII를 사용하여 누수 방지"