try 블록

try 블록 (예외 처리 구문)

예외를 잡아 처리하려면 던질 수 있는 코드를 try 블록으로 감싸고, 그에 연관된 핸들러(handler)를 붙여줘요. try 블록 안에서 던져진 예외는 연관된 핸들러가 잡을 수 있어요.

출처: cppreference

본문

문법 (Syntax)

표기 의미
try compound-statement handler-seq (1)
try ctor-initializer (optional) compound-statement handler-seq (2)
  1. 일반적인 try 블록.
  2. 함수 try 블록. 이때 compound-statement는 함수 본문의 복합문(compound statement) 구성 요소여야 해요.
  • compound-statement — 복합문
  • handler-seq — 비어 있지 않은 핸들러들의 시퀀스
  • ctor-initializer — 멤버 초기화 목록(생성자에만 해당)

일반적인 try 블록 (Ordinary try block)

일반적인 try 블록은 하나의 문장(statement)이에요.

그 복합문에서 예외가 던져지면, 그 예외는 handler-seq의 핸들러들과 비교돼요.

void f()
{
    throw 1;     // 아래 핸들러로 처리되지 않음
    try
    {
        throw 2; // 연관된 핸들러로 처리됨
    }
    catch (...)
    {
        // 예외 2를 처리
    }
    throw 3;     // 위 핸들러로 처리되지 않음
}

함수 try 블록 (Function try block)

함수 try 블록은 함수 본문의 특별한 종류예요.

그 복합문이나 ctor-initializer(있다면)에서 예외가 던져지면, 그 예외는 handler-seq의 핸들러들과 비교돼요.

int f(bool cond)
{
    if (cond)
        throw 1;
    return 0;
}

struct X
{
    int mem;

    X() try : mem(f(true)) {}
    catch (...)
    {
        // 예외 1을 처리
    }

    X(int) try
    {
        throw 2;
    }
    catch (...)
    {
        // 예외 2를 처리
    }
};

정적 저장 기간을 가진 객체의 소멸자나, 정적 저장 기간을 가진 비블록 변수와 연관된 객체의 생성자에서 던져진 예외는 main 함수의 함수 try 블록이 잡지 못해요. (C++11부터) 마찬가지로 스레드 저장 기간을 가진 객체의 소멸자나, 스레드 저장 기간을 가진 비블록 변수와 연관된 객체의 생성자에서 던져진 예외는 그 스레드의 초기 함수의 함수 try 블록이 잡지 못해요.

함수 try 블록의 핸들러의 복합문 끝까지 흘러가는 것(flowing off the end)은, 그 함수가 생성자나 소멸자(아래 참조)가 아니라면, 그 함수 try 블록의 복합문 끝까지 흘러가는 것과 동등해요.

생성자와 소멸자의 try 블록 (Constructor and destructor try block)

클래스 C에 대해, 그 생성자나 소멸자 정의의 함수 본문이 함수 try 블록이고, C의 하위 객체(subobject)의 초기화나 파괴 중에 예외가 던져진다면, 그 예외 역시 함수 try 블록의 handler-seq의 핸들러들과 비교돼요.

int f(bool cond = true)
{
    if (cond)
        throw 1;
    return 0;
}

struct X
{
    int mem = f();

    ~X()
    {
        throw 2;
    }
};

struct Y
{
    X mem;

    Y() try {}
    catch (...)
    {
        // 예외 1을 처리
    }

    ~Y() try {}
    catch (...)
    {
        // 예외 2를 처리
    }
};

생성자나 소멸자의 함수 try 블록 핸들러에서 그 객체의 어떤 비정적 멤버나 기저 클래스를 참조하면 동작이 정의되지 않아요.

생성자의 함수 try 블록 핸들러에 return 문이 나타나면 프로그램은 ill-formed예요.

제어가 생성자나 소멸자의 함수 try 블록 핸들러 끝에 도달하면, 현재 처리 중인 예외가 재던져져요.

제어 흐름 (Control flow)

try 블록의 복합문은 **제어 흐름 제한 문장(control-flow-limited statement)**이에요.

void f()
{
    goto label;     // error
    try
    {
        goto label; // OK
        label: ;
    }
    catch (...)
    {
        goto label; // error
    }
}

점프 문(goto, break, return, continue)으로 try 블록(그 핸들러 포함) 밖으로 제어를 옮길 수 있어요. 이때 try 블록에 선언된 각 변수는 그 선언을 직접 포함하는 문맥에서 파괴돼요.

try
{
    T1 t1;
    try
    {
        T2 t2;
        goto label; // t2를 먼저 파괴, 그다음 t1
    }
    catch(...)
    {
        // t2를 파괴하는 동안 예외가 던져지면 실행됨
    }
}
catch(...)
{
    // t1을 파괴하는 동안 예외가 던져지면 실행됨
}
label: ;

키워드 (Keywords)

try

참고 (Notes)

기능 검사 매크로(feature-test macro)는 다음과 같아요.

기능 검사 매크로 표준 기능
__cpp_constexpr 201907L (C++20) constexpr 함수 안의 try 블록

결함 보고 (Defect reports)

다음의 동작 변경 결함 보고가 이전에 공개된 C++ 표준들에 소급 적용됐어요.

DR 적용 공개된 동작 올바른 동작
CWG 98 C++98 switch 문이 try 블록의 복합문 안으로 제어를 옮길 수 있었음 금지
CWG 1167 C++98 소멸자의 함수 try 블록이 기저나 멤버 소멸자의 예외를 잡을지가 불특정이었음 그러한 예외가 잡힘

같이 보기 (See also)

  • 예외 던지기(Throwing exceptions)
  • 예외 처리(Handling exceptions)

더 알아보기

  • throw 표현식: 예외를 던지는 방법.
  • 예외 처리 (Exception handling): catch 핸들러와 예외 메커니즘의 전체 구조.