예외 처리

MwG·2025년 3월 20일

C++

목록 보기
9/14

✅ 1. 예외(Exception)란?

C++에서 예외(Exception)는 프로그램 실행 중 오류 또는 비정상적인 상황이 발생했을 때 이를 감지하고 적절히 처리하는 메커니즘이다.
예외 처리를 사용하면 프로그램이 비정상적으로 종료되는 것을 방지하고, 오류를 보다 체계적으로 관리할 수 있다.

✅ 2. throw, try, catch 기본 개념

C++ 예외 처리는 세 가지 주요 키워드로 구성된다.

throw 예외를 발생시킬 때 사용
try 예외 발생 가능성이 있는 코드를 감싸는 블록
catch 예외가 발생했을 때 실행할 코드 블록

✅ 3. 예외 처리 기본 구조

try {
    // 예외가 발생할 가능성이 있는 코드
    throw 42;  // 예외 발생
} 
catch (int e) {  
    // 예외 처리 코드
    std::cout << "Caught exception: " << e << std::endl;
}

✔ throw → 예외 발생 시, 예외 객체를 전달함
✔ try → 예외 발생 가능성이 있는 코드 블록을 감싸줌
✔ catch → 발생한 예외를 받아 처리

✅ 4. 예제 코드: 예외 발생 및 처리

#include <iostream>

void testFunction() {
    std::cout << "Throwing an exception..." << std::endl;
    throw std::runtime_error("Something went wrong!");  // 예외 발생
}

int main() {
    try {
        testFunction();
    } 
    catch (const std::runtime_error& e) {
        std::cout << "Caught exception: " << e.what() << std::endl;
    }
    
    std::cout << "Program continues..." << std::endl;
    return 0;
}

🔹 실행 결과:
Throwing an exception...(예외 발생)
Caught exception: Something went wrong!(해당 예외 타입에 대한 정보를 받아 실행)
Program continues...
✔ 예외가 발생하면 즉시 catch 블록으로 이동하여 처리됨
✔ 예외 처리 후에도 프로그램이 정상적으로 실행됨

✅ 5. 여러 개의 catch 블록 사용

예외 타입에 따라 다른 방식으로 처리 가능

try {
    throw 42;  // 예외 발생
} 
catch (int e) {
    std::cout << "Caught an integer: " << e << std::endl;
} 
catch (const std::runtime_error& e) {
    std::cout << "Caught a runtime_error: " << e.what() << std::endl;
} 
catch (...) {  // 모든 예외를 처리하는 블록 switch의 default처럼
    std::cout << "Caught an unknown exception" << std::endl;
}

특정 예외 타입에 맞는 catch 블록이 실행됨
catch (...)는 모든 예외를 처리하는 블록 (예외 종류를 모를 때 사용)

✅ 6. 예외 전파(Exception Propagation)

예외는 함수를 넘어서 상위 함수로 전파될 수 있다.

#include <iostream>

void functionA() {
    throw std::runtime_error("Error in functionA");
}

void functionB() {
    functionA();  // functionA에서 예외 발생
}

int main() {
    try {
        functionB();  // functionB가 호출됨
    } 
    catch (const std::runtime_error& e) {
        std::cout << "Caught exception: " << e.what() << std::endl;
    }
}

🔹 실행 결과:
Caught exception: Error in functionA
✔ 예외가 발생하면 functionA → functionB → main으로 전파됨
✔ main에서 예외가 처리되지 않으면 프로그램이 비정상 종료됨

만약 부모,자식 클래스에 대해서 받을 경우 catch순서에 부모 클래스를 먼저 둘 경우
Parent& p = Child()✅
Child& p = Parent()❌
도 가능하므로 자식클래스 예외타입에 대해서도 부모 클래스에 대한 catch가 실행되므로 자식 클래스를 앞에 두는 것이 좋다.

✅ 7. 스택 풀기 (Stack Unwinding)

스택 풀기(Stack Unwinding)란 예외가 발생하여 함수가 종료될 때, 지역 변수들이 자동으로 소멸되는 과정을 의미한다.

📌 스택 풀기의 원리:
예외 발생 시, 현재 함수가 즉시 종료됨.
지역 변수들의 소멸자가 자동으로 호출됨.
예외가 상위 함수로 전파되면서, 그 과정에서 할당된 모든 지역 변수들이 해제됨.
catch 블록에서 예외를 처리하면 예외 전파가 멈춤.
📌 예제 (소멸자 호출 확인)

#include <iostream>

struct Test {
    std::string name;
    Test(std::string n) : name(n) { std::cout << name << " created\n"; }
    ~Test() { std::cout << name << " destroyed\n"; }
};

void functionA() {
    Test a("A");
    throw std::runtime_error("Exception in functionA");
}

void functionB() {
    Test b("B");
    functionA();
}

int main() {
    try {
        functionB();
    } 
    catch (const std::runtime_error& e) {
        std::cout << "Caught exception: " << e.what() << std::endl;
    }
}

🔹 실행 결과:
B created
A created
A destroyed
B destroyed
Caught exception: Exception in functionA
✔ 예외가 발생하면 지역 변수들이 역순으로 소멸됨.
✔ 스택 풀기가 동작하여 자원 누수가 방지됨.
유의할 점 -> 생성자에서 예외 발생 시 소멸자가 호출되지 않음!@

✅ 8. 사용자 정의 예외 클래스

C++에서는 std::exception을 상속받아 사용자 정의 예외 클래스를 만들 수 있다.

#include <iostream>
#include <stdexcept>

class MyException : public std::exception {
public:
    const char* what() const noexcept override {
        return "Custom exception occurred!";
    }
};

void test() {
    throw MyException();
}

int main() {
    try {
        test();
    } 
    catch (const MyException& e) {
        std::cout << "Caught: " << e.what() << std::endl;
    }
}

✔ std::exception을 상속받아 what()을 오버라이드하여 예외 메시지를 정의 가능.
✔ 사용자 정의 예외를 통해 더 세밀한 예외 처리가 가능.

what()->예외 발생 시 해당 예외에 대한 설명 메시지(문자열)를 반환하는 역할

✅ 9. noexcept와 예외 처리

noexcept 키워드를 사용하면 함수에서 예외가 발생하지 않음을 명시할 수 있다.

void safeFunction() noexcept {
    std::cout << "This function never throws exceptions.\n";
}

✔ noexcept가 붙은 함수에서 예외가 발생하면 프로그램이 강제 종료됨.

✔ noexcept가 붙었다고 해서 절대 예외를 발생시키지 않는 것은 아니다.
-> 컴파일러가 예외를 발생시키지 않는다고 생각하고 컴파일 하는 것임.

-✔ 예외를 절대 발생시키지 않는 함수에 사용하면 최적화에 도움이 됨.
✔ C++11 부터 소멸자는 기본적으로 noexcept임.

추가자료 <stdexcept.h>

MS <stdexcept.h>에 대한 자세한 자료들 클래스들 등등...

0개의 댓글