C++

[C++] try-catch 문

seungwoo-dev 2026. 5. 21. 13:35

안녕하세요! 오늘은 C++ 프로그램의 안정성을 높이는 데 필수적인 예외 처리(Exception Handling) 메커니즘, try-catch 문에 대해 자세히 알아보겠습니다.

코드 문법은 완벽하지만, 프로그램을 실행하다 보면 존재하지 않는 파일을 열려고 하거나, 배열의 인덱스를 벗어나거나, 0으로 나누는 등 예상치 못한 상황(Runtime Error)이 발생하곤 합니다. C++에서는 이러한 예외 상황을 어떻게 우아하게 처리하는지 기초부터 실무 팁까지 정리해 보았습니다.

1. 예외 처리의 핵심 3요소: try, catch, throw

C++ 예외 처리는 크게 세 가지 키워드로 이루어집니다.

  • try: 예외가 발생할 가능성이 있는 코드 블록을 지정합니다.
  • throw: 예외가 발생했음을 알리며, 예외 객체를 던집니다.
  • catch: 던져진 예외를 받아서 처리하는 플랜 B 코드 블록입니다.

📌 기본 문법 구조

C++
 
try {
    // 1. 실행하고 싶은 코드 (예외 발생 가능 지역)
    if (조건) {
        throw 예외객체; // 2. 예외가 발생하면 catch로 던짐
    }
} 
catch (const 예외타입& e) {
    // 3. 예외를 잡아 처리하는 곳
}

2. 실전 예제 코드로 이해하기

가장 흔히 접할 수 있는 '0으로 나누기(Divide by Zero)' 상황을 C++ 코드로 구현해 보겠습니다.

C++
 
#include <iostream>
#include <stdexcept> // 표준 예외 클래스 포함

double divide(double numerator, double denominator) {
    if (denominator == 0.0) {
        // C++ 표준 예외 클래스인 std::runtime_error 사용
        throw std::runtime_error("Error: 0으로 나눌 수 없습니다!"); 
    }
    return numerator / denominator;
}

int main() {
    double num = 10.0;
    double den = 0.0;

    try {
        std::cout << "나눗셈을 시도합니다..." << std::endl;
        double result = divide(num, den);
        
        // 예외가 발생하면 아래 코드는 실행되지 않고 즉시 catch 블록으로 건너뜁니다.
        std::cout << "계산 결과: " << result << std::endl; 
    } 
    catch (const std::runtime_error& e) {
        // 던져진 std::runtime_error 객체를 참조로 받아와 메시지 출력
        std::cerr << "[예외 발생] " << e.what() << std::endl;
    }

    std::cout << "프로그램이 죽지 않고 정상적으로 종료됩니다." << std::endl;
    return 0;
}

실행 결과:

Plaintext
 
나눗셈을 시도합니다...
[예외 발생] Error: 0으로 나눌 수 없습니다!
프로그램이 죽지 않고 정상적으로 종료됩니다.

3. C++ 예외 처리의 핵심: 스택 되감기 (Stack Unwinding)

C++에서 try-catch가 다른 언어와 차별화되는 가장 중요한 특징 중 하나는 스택 되감기(Stack Unwinding)입니다.

try 블록 내부의 함수에서 예외가 발생해 throw가 실행되면, 프로그램은 그 예외를 처리할 수 있는 catch 블록을 찾을 때까지 함수 호출 스택을 거꾸로 거슬러 올라갑니다.

이때 중요한 점은, 스택을 빠져나오면서 해당 지역(Local)에 생성되었던 모든 객체들의 소멸자(Destructor)가 자동으로 호출된다는 것입니다. 덕분에 메모리 누수나 자원 고립을 방지할 수 있습니다. (단, RAII 패턴을 잘 지켰을 때의 이야기입니다.)

4. C++ 개발자를 위한 실무 팁 (Best Practices)

① catch할 때는 가능한 '상수 참조(const reference)'를 사용하세요

C++
 
// ❌ 비추천 (객체 복사가 일어나 성능 저하 및 슬라이싱 문제 발생 가능)
catch (std::runtime_error e) 

//  추천 (복사 없이 안전하게 참조)
catch (const std::runtime_error& e) 

② 모든 예외를 잡는 다중 catch문과 만능 catch (...)

C++은 여러 개의 catch 블록을 둘 수 있으며, 위에서부터 순서대로 매칭됩니다. 따라서 자식 클래스 예외를 위에, 부모 클래스 예외를 아래에 배치해야 합니다. 어떤 예외든 다 잡고 싶다면 ...을 사용합니다.

C++
 
try {
    // ...
} catch (const std::invalid_argument& e) {
    // 특정 예외 처리
} catch (const std::exception& e) {
    // 모든 표준 예외 처리
} catch (...) {
    // 표준 예외가 아닌 모든 것들을 처리 (최후의 보루)
}

③ 예외를 던지지 않는 함수는 noexcept를 선언하세요

C++11부터 도입된 noexcept 키워드를 함수 뒤에 붙이면, 컴파일러는 이 함수가 예외를 던지지 않을 것임을 확신하고 더 효율적인 코드를 생성(최적화)합니다. 성능이 중요한 C++ 개발에서 매우 중요한 습관입니다.

C++
 
void ⚡️미친_성능_함수() noexcept {
    // 절대 예외를 던지지 않는 코드
}

마치며

C++에서 try-catch는 프로그램의 비정상 종료를 막아주는 강력한 도구이지만, 예외가 발생했을 때 스택을 되감는 비용이 존재하므로 정말 '예외적인 상황'에만 사용하는 것이 좋습니다. 일반적인 조건문(if-else)으로 처리할 수 있는 비즈니스 로직은 조건문으로 처리하는 것이 성능상 유리합니다.

궁금하신 점이나 의견이 있다면 댓글로 남겨주세요. 도움이 되셨다면 공감 부탁드립니다! 😊