try 블록
try 블록 (예외 처리 구문)
예외를 잡아 처리하려면 던질 수 있는 코드를 try 블록으로 감싸고, 그에 연관된 핸들러(handler)를 붙여줘요. try 블록 안에서 던져진 예외는 연관된 핸들러가 잡을 수 있어요.
출처: cppreference
본문
문법 (Syntax)
| 표기 | 의미 |
|---|---|
try compound-statement handler-seq |
(1) |
try ctor-initializer (optional) compound-statement handler-seq |
(2) |
- 일반적인
try블록. - 함수
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 핸들러와 예외 메커니즘의 전체 구조.