C++ 예외 처리

SOEUN CHOI·2022년 6월 15일
0

C++_study

목록 보기
9/15

씹어먹는 C++

12장 c++에서의 예외 처리 613p-629p


예외(exception)

정상적인 상황에서 벗어난 모든 예외적인 상황

문법 상 틀린 것이 없는 코드라도 실제로 실행 시 오류발생 가능성 있음

  • 예외를 계속 체크하는 데 있어서 시스템 로드가 생김
    성능이 떨어지면 잘 안씀...

throw

예외가 발생 사실을 명시적으로 나타냄

  • 예외로 전달하고 싶은 객체 throw
    여러 종류 예외 라이브러리 사용
  • throw 한 위치에서 즉시 함수가 종료 후 예외 처리 부분까지 점프
    점프하며서 stack 에 생성되었던 객체들을 빠짐없이 소멸

example code

const T& at(size_t index) const {
  if (index >= size) {
    // 예외를 발생시킨다!
    throw std::out_of_range("vector 의 index 가 범위를 초과하였습니다.");
  }
  return data[index];
}

try 와 catch

try
무언가 예외가 발생할만한 코드가 실행

  • 예외가 없다면
    catch 문은 무시
  • 예외가 있다면
    stack 에 생성된 모든 객체들의 소멸자들이 호출되고, 가장 가까운 catch 문으로 점프

catch
throw 된 예외를 받는 부분
정의된 예외의 꼴에 맞는 객체로 받음

template <typename T>
class Vector {
public:
  Vector(size_t size) : size_(size) {
    data_ = new T[size_];
    for (int i = 0; i < size_; i++) {
      data_[i] = 3;
    }
  }
  const T& at(size_t index) const {
    if (index >= size_) {
      throw std::out_of_range("vector 의 index 가 범위를 초과하였습니다.");
    }
    return data_[index];
  }~
  Vector() { delete[] data_; }
private:
  T* data_;
  size_t size_;
}; 

int main() {
  Vector<int> vec(3);
  
  int index, data = 0;
  std::cin >> index;
  
  try {
  data = vec.at(index);
  } catch (std::out_of_range& e) {
  std::cout << "예외 발생 ! " << e.what() << std::endl;
  }
  // 예외가 발생하지 않았다면 3을 이 출력되고, 예외가 발생하였다면 원래 data 에
  // 들어가 있던 0 이 출력된다.
  std::cout << "읽은 데이터 : " << data << std::endl;
}

스택 풀기 (stack unwinding)

catch 로 점프 하면서 스택 상에서 정의된 객체들을 소멸
각 객체의 소멸자 호출하여 소멸

여러 종류의 예외 받기

catch문
여러 종류의 예외들을 받기 가능
각기 다른 타입으로 throw 하면 작동하는 catch가 달라짐

  • 기반 파생 클래스의 catch 주의
    Parent catch 를 Child catch 보다 뒤에 쓰자

    > 기반 클래스 레퍼런스나 포인터에 파생 클래스 객체를 정의시
    catch에서 기반 클래스를 catch를 타게됨

example code

int func(int c) {
  if (c == 1) {
  	throw 10;
  } else if (c == 2) {
  	throw std::string("hi!");
  } else if (c == 3) {
  	throw 'a';
  } else if (c == 4) {
  	throw "hello!";
  }
  return 0;
}

int main() {
  int c;
  std::cin >> c;
  
  try {
  	func(c);
  } catch (char x) {
  	std::cout << "Char : " << x << std::endl;
  } catch (int x) {
  	std::cout << "Int : " << x << std::endl;
  } catch (std::string& s) {
  	std::cout << "String : " << s << std::endl;
  } catch (const char* s) {
  	std::cout << "String Literal : " << s << std::endl;
  }
}

모든 예외 받기

어떤 예외를 throw but, 받는 catch 가 없을 수 있음

  • catch(...)
    try 안에서 발생한 모든 예외들을 받음

example code


int func(int c) {
  if (c == 1) {
  	throw 1;
  } else if (c == 2) {
  	throw "hi";
  } else if (c == 3) {
  	throw std::runtime_error("error");
  }
  return 0;
}

int main() {
  int c;
  std::cin >> c;

  try {
  	func(c);
  } catch (int e) {
  	std::cout << "Catch int : " << e << std::endl;
  } catch (...) {
  	std::cout << "Default Catch!" << std::endl;
  }
}

noexcept

명시적으로 함수가 예외 발생 시키지 않음을 표현

int foo() noexcept {}

물론 키워드가 있다 해서 반드시 예외를 던지지 않지는 않음
만약 예외를 던지게 예외가 처리되지 않고 비정상 종료됨

  • C++ 11 에서 부터 소멸자들은 기본적으로 noexcept
    절대로 소멸자에서 예외를 던질 수 없음
profile
soeun choi

0개의 댓글