C++ 예외 처리 마스터: try, catch, throw 실전 예제
C++ 예외 처리란?
예외 처리는 C++ 프로그램이 예기치 않은 런타임 오류로부터 우아하게 복구할 수 있게 합니다. 오류 발생 시 제어가 특별한 핸들러로 점프하여 어떻게 대응할지 결정합니다.
잠재적으로 문제가 될 수 있는 코드를 try 블록으로 감싸고 그 뒤에 하나 이상의 catch 절을 두면, 프로그램에 예외적 상황을 관리할 명확한 경로를 제공합니다.
예외가 던져지지 않으면 try 블록이 정상 실행되고 핸들러들은 우회됩니다.
이 튜토리얼에서 배울 내용:
- 예외 처리가 무엇이고 왜 중요한가
- 핵심 키워드:
throw, catch, try
- 문법과 일반적인 패턴
- C++ 표준 라이브러리 정의 표준 예외
- 사용자 정의 예외 생성 및 사용법
왜 예외 처리인가?
예외 처리는 여러 실질적 이점을 제공합니다:
- 에러 처리 로직을 일반 코드와 분리하여 가독성과 유지보수성 향상
- 함수가 자신이 신경 쓰는 예외만 노출하게 하고, 호출자가 나머지를 처리 가능
핵심 예외 처리 키워드
세 키워드가 C++ 예외 처리의 중추를 이룹니다:
- throw – 예외 객체를 생성하여 오류 상태 알림
- catch – 예외를 가로채고 대응 코드 제공
- try – 예외를 던질 수 있는 코드 영역 표시
try 블록 안의 코드를 보호된 코드라 하며, 예외를 던지면 해당 catch 블록이 실행됩니다.
문법
try {
// 보호된 코드
} catch (Exception_Name exception1) {
// exception1 처리
} catch (Exception_Name exception2) {
// exception2 처리
} // ... 더 많은 catch 블록
- 단일
try 뒤에 여러 catch 절 가능
- 각
catch 절의 타입이 잡을 예외를 지정
catch 내부에서 선택한 식별자로 잡은 예외 참조 가능
예제 1: 벡터 요소 범위 밖 접근
#include<iostream>
#include<vector>
using namespace std;
int main() {
vector<int> vec;
vec.push_back(0);
vec.push_back(1);
try {
vec.at(2); // 범위 밖
} catch (exception& ex) {
cout << "Exception occurred!" << endl;
}
return 0;
}
출력:

코드 스크린샷:

코드 분석:
- I/O와 컨테이너 지원을 위해
iostream과 vector 포함
- 완전 자격 이름 방지를 위해
std 네임스페이스 사용
vector<int> 인스턴스화 및 채우기
try 블록 내부에서 벡터 범위 밖 요소 접근 시도
- 표준
std::exception을 잡고 메시지 출력
main에서 반환
예제 2: 0으로 나누기 처리
#include <iostream>
using namespace std;
double zeroDivision(int x, int y) {
if (y == 0) {
throw "Division by Zero!";
}
return static_cast(x) / y;
}
int main() {
int a = 11;
int b = 0;
double c = 0;
try {
c = zeroDivision(a, b);
cout << c << endl;
} catch (const char* message) {
cerr << message << endl;
}
return 0;
}
출력:

코드 스크린샷:

코드 분석:
- 0으로 나누면 C-문자열을 던지는
zeroDivision 정의
- 함수를
try 블록 내부에서 호출하고 결과 출력
- 문자열 예외를 잡고 에러 메시지 출력
C++ 표준 예외

표준 라이브러리는 <exception>에 풍부한 예외 계층을 선언합니다. 가장 자주 사용되는 것들:
| 예외 | 설명 |
| std::exception | 모든 표준 예외의 기본 클래스 |
| std::bad_alloc | new 할당 실패 시 던져짐 |
| std::bad_cast | dynamic_cast 실패 시 던져짐 |
| std::bad_exception | 예기치 않은 예외 알림용 |
| std::bad_typeid | 널인 다형 타입의 glvalue에 typeid 적용 시 |
| std::logic_error | 프로그래머가 감지해야 할 오류 |
| std::domain_error | 수학 함수의 유효하지 않은 도메인 |
| std::invalid_argument | 함수가 유효하지 않은 인수 수신 |
| std::length_error | 너무 큰 문자열 생성 시도 |
| std::out_of_range | vector::at에서 인덱스 범위 초과 시 |
| std::runtime_error | 다른 카테고리로 잡히지 않는 런타임 오류 |
| std::overflow_error | 수학적 오버플로 발생 |
| std::range_error | 연산에 대한 값이 범위 밖 |
| std::underflow_error | 수학적 언더플로 발생 |
사용자 정의 예외
std::exception 기본 클래스를 확장하여 도메인별 에러 타입을 만들 수 있습니다. what()을 오버라이드하면 설명 메시지를 제공합니다.
예제: 사용자 정의 예외
#include <iostream>
#include <exception>
using namespace std;
class NewException : public exception {
public:
const char* what() const noexcept override {
return "newException occurred";
}
} newex;
int main() {
try {
throw newex;
} catch (exception& ex) {
cout << ex.what() << '\n';
}
return 0;
}
출력:

코드 스크린샷:

코드 분석:
NewException을 std::exception에서 파생하고 what() 오버라이드
- 던질 객체
newex 인스턴스화
try 블록 내부에서 newex 던지기
std::exception 참조로 잡고 what()으로 메시지 출력
핵심 정리
- 예외 처리는 런타임 오류로부터 복구해야 하는 견고한 C++ 애플리케이션에 필수적입니다.
- 코드 보호를 위해
try, 대응을 위해 catch, 문제 알림을 위해 throw 사용
- 풍부한 표준 예외 세트 활용, 맞춤 에러 타입 필요 시
std::exception 확장
- 에러 처리 로직을 비즈니스 로직과 분리하여 더 깔끔하고 유지보수하기 쉬운 코드 작성