C++/C++ try catch, throw, what, exception

exception, what

재윤 2024. 1. 26. 11:50
반응형

→ if-else문을 통해 예외를 인지하게 한 후 직접 throw를 던졌었지만 문제가 생기면 std::exception 클래스를 통해 시스템 상 내부에서 알아서 발생한 예외를 throw 한다.

  • 예외(exception)은 프로그램 실행 중에 예기치 않은 상황이나 오류가 발생했을 때 발생하는 이벤트를 가리킵니다. 예외는 프로그램이 비정상적으로 종료되는 것을 방지하고 오류를 처리하는 메커니즘을 제공

 

→ C++ 표준 클래스로 예외의 여러 종류들을 나타내는 여러 자식 클래스들을 두고 있다.

• runtime_error 클래스, logic_error 클래스 등등 C++ 표준의 exception 클래스 를 상속받고 있다.

#include <iostream>
#include <string>
#include <exception>

int main()
{
   try
   {
       std::string s;
       s.resize(-1);  // 예외 발생
   }
   catch (const std::exception & e)
   {
       std::cout << typeid(e).name() << std::endl;
       std::cerr << e.what() << std::endl;
   }

   return 0;
}

결과

class std::length_error
string too long

 

설명

  • throw 없이도 시스템상 내부에서 알아서 예외 종류에 알맞는 std::exception 클래스의 자식 클래스를 던져 준다.
    • 길이에 대한 에러이므로 std::exception 클래스의 자식 클래스 중 하나인 std::length_error 예외 클래스 객체가 던져진다.
      • throw std::length_error(s)이 숨겨져 있는 것이나 마찬가지.
    • catch (const std::exception & e) 에서 이를 받는다.
  • typeid(e).name()
    • “class std::length_error” 출력
(const std::exception& e)

: 괄호 안에 있는 부분은 예외 객체를 받아들이고 처리하기 위한 매개 변수입니다. 이 부분은 여러 부분으로 나눠서 설명가능.

  • const: **e**라는 예외 객체를 수정하지 않고 읽기 전용으로 사용하겠다는 것을 나타냅니다. 즉, 예외 객체를 변경하지 않는다는 의미입니다.
  • std::exception&: std::exception 클래스나 이 클래스를 상속받은 클래스의 예외를 처리하겠다는 것을 나타냅니다. std::exception은 C++ 표준 라이브러리에서 제공하는 예외 클래스의 기본 클래스이다. 이렇게 하면 모든 std::exception 타입의 예외를 처리할 수 있습니다.
  • e: 예외 객체를 나타내는 변수 이름입니다. 이 변수를 통해 예외 객체의 정보에 접근할 수 있습니다.

 

정리

catch (const std::exception& e)는 std::exception 클래스나 이 클래스를 상속받은 예외를 잡아서 **e**라는 이름의 변수로 처리하겠다는 의미. 예외가 발생하면 이 블록이 실행되고, e 변수를 사용하여 예외 객체의 정보에 접근하거나 출력 가능.

 

what

  • 예외 종류에 맞는 에러 원인 메시지를 리턴하는 기능을 하는 함수이다.
    • 에러 메세지를 리턴하므로 리턴 타입은 const char *
  • std::exception 클래스의 모든 자식 클래스는 virtual 가상 함수인 what() 함수를 오버라이딩 한다. → 가상함수를 붙이는 이유는 다른 자식에서도 사용할 수 있기 때문
    • e.what()
      • “string too long” 출력
        • std::length_error 클래스에서는 what() 함수를 “string too long” 출력 하도록 오버라이딩 해놨기 때문에 이렇게 나온 것!

 

std::exception 상속 받는 사용자 정의 클래스 만들기

  • std::exception를 상속 받은 클래스를 정의하고 what 함수를 아래와 같이 오버라이딩 한다.
#include <iostream>
#include <exception>

class DivisionByZeroException : public std::exception {
public:
    const char* what() const  throw()
		{
        return "Division by zero exception";
    }
};

int main() {
    int numerator, denominator;

    std::cout << "Enter the numerator: ";
    std::cin >> numerator;

    std::cout << "Enter the denominator: ";
    std::cin >> denominator;

    try {
        if (denominator == 0) {
            throw DivisionByZeroException(); // 사용자 정의 예외 발생
        }

        int result = numerator / denominator;
        std::cout << "Result: " << result << std::endl;
    } catch (const DivisionByZeroException& ex) {
        std::cerr << "Exception caught: " << ex.what() << std::endl;
    }

    return 0;
}

 

const char* what() const 의미를 알아보자

const char* what() const throw();
  • what 함수는 std::exception 클래스에서 상속받은 가상 함수이다. 이 함수는 예외 객체에 대한 설명을 문자열로 반환하는 역할을 함. 여기서 **const char *** 형태의 포인터를 반환함.
  • const throw()는 이 함수가 예외를 던지지 않음을 나타냄. 즉, what 함수는 예외가 발생했을 때 안전하게 호출될 수 있는 함수입니다.

사용자 정의 예외 클래스를 만들 때 what 함수를 재정의하여 예외 객체에 대한 설명을 제공하거나 사용자 정의한 예외 클래스에 대한 정보를 포함 가능. 이 설명은 예외가 처리될 때 예외 메시지로 출력되거나 로깅되는 데 사용됨.

DivisionByZeroException 클래스의 객체가 예외로 던져질 때 what 함수를 통해 예외 설명을 제공할 수 있다. 이 설명은 예외가 발생한 상황에 대한 정보를 포함하고 있을 것이며, 예외 처리 코드에서 이 정보를 활용 가능.

 

다중 Catch으로 구현

#include <iostream>
#include <exception>

class DivisionByZeroException : public std::exception {
public:
    const char* what() const noexcept override {
        return "Division by zero exception";
    }
};

class NegativeNumberException : public std::exception {
public:
    const char* what() const noexcept override {
        return "Negative number exception";
    }
};

int main() {
    int numerator, denominator;

    std::cout << "Enter the numerator: ";
    std::cin >> numerator;

    std::cout << "Enter the denominator: ";
    std::cin >> denominator;

    try {
        if (denominator == 0) {
            throw DivisionByZeroException(); // DivisionByZeroException 예외 발생
        }

        if (numerator < 0 || denominator < 0) {
            throw NegativeNumberException(); // NegativeNumberException 예외 발생
        }

        int result = numerator / denominator;
        std::cout << "Result: " << result << std::endl;
    } catch (const DivisionByZeroException& ex) {
        std::cerr << "DivisionByZeroException caught: " << ex.what() << std::endl;
    } catch (const NegativeNumberException& ex) {
        std::cerr << "NegativeNumberException caught: " << ex.what() << std::endl;
    } catch (const std::exception& ex) {
        std::cerr << "Generic exception caught: " << ex.what() << std::endl;
    }

    return 0;
}
  • 두 가지 예외 유형(DivisionByZeroExceptionNegativeNumberException)을 처리하기 위해 catch 블록이 추가됨.
  • catch 블록은 해당 예외 유형을 처리하며, 다른 예외 유형에 대한 처리는 따로 구현되어있다.
  • 마지막의 catch (const std::exception& ex) 블록은 모든 예외 유형을 처리하기 위한 일반적인 예외 처리 블록. 이 블록은 다른 catch 블록에서 처리되지 않은 예외에 대한 예외 처리를 담당합니다.

결과

Enter the numerator: 10
Enter the denominator: 2
Result: 5

Enter the numerator: -8
Enter the denominator: 4
NegativeNumberException caught: Negative number exception

Enter the numerator: 6
Enter the denominator: 0
DivisionByZeroException caught: Division by zero exception

 

글은 이 분의 글에서 공부한 것과 추가적으로 공부한 것으로 작성하였습니다.

C++ Chapter 14.4 : std::exception

 

C++ Chapter 14.4 : std::exception

인프런에 있는 홍정모 교수님의 홍정모의 따라 하며 배우는 C++ 강의를 듣고 정리한 필기입니다. 😀 🌜 [홍정모의 따라 하며 배우는 C++]강의 들으러 가기!

ansohxxn.github.io

 

반응형

'C++ > C++ try catch, throw, what, exception' 카테고리의 다른 글

Try Catch, throw  (2) 2024.01.26