[따배C++] 14. 예외처리
Created: June 6, 2021 11:26 AM
Tag: exception handling, function try, rethrow, stack unwinding, std::exception
14.1 예외처리의 기본 exception handling
try
, catch
(던져진 예외를 받아서 처리한다), throw
(예외를 던진다) 구문을 통해 예외처리를 할 수 있다. 이 방법은 문법적으로 깔끔하지만 퍼포먼스에 불리하기 때문에 상황에 따라 사용이 제한되어야 한다. 또한, 자료형에 따라 엄밀하게 작동(runtime error)하기 때문에 주의가 필요하다. ellipses
구문을 통해 이를 방지할 수 있다.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(void)
{
double x;
cin >> x;
try
{
if (x < 0.0) throw std::string("Negative input");
cout << std::sqrt(x) << endl;
}
catch (std::string error_message) // <- 자료형에 주의
{
// do something to respond
cout << error_message << endl;
}
return (0);
}
14.2 예외처리와 스택 되감기 stack unwinding
#include <iostream>
using namespace std;
void last() throw(int) // throw(int) <- exception specifier: int type의 예외를 던질 수도 있음을 명시!
// 불필요한것 아니냐는 견해
// 예외를 던질 가능성이 있는 함수
{
cout << "last " << endl;
cout << "throws exception" << endl;
throw -1; // 다음부분 실행하지 않고 throw
cout << "end last " << endl;
}
void third()
{
cout << "third" << endl;
last(); // 다음부분 실행하지 않고 throw
cout << "end third" << endl;
}
void second()
{
cout << "second" << endl;
try
{
third();
}
catch (double) // throw는 int로 되었는데 double로 밖에 catch하지 못한다면 계속해서 날아간다
{
cerr << "second caught double exception" << endl;
}
cout << "end second " << endl;
}
void first()
{
cout << "first" << endl;
try
{
second();
}
catch (int) // catch!
{
cerr << "first caught int exception" << endl;
}
cout << "end first" << endl;
}
int main(void)
{
cout << "start" << endl;
try
{
first();
}
catch (int)
{
cerr << "main caught int exception" << endl;
// clog
}
// uncaught exceptions 못잡는 오류가 발생하는 경우
catch (...) // catch-all handlers
{
cerr << "main caught ellipses exception" << endl;
}
cout << "end main" << endl;
return (0);
}
14.3 예외 클래스(사용자 정의 자료형)와 상속 시 주의점
#include <iostream>
using namespace std;
void last() throw(int) // throw(int) <- exception specifier: int type의 예외를 던질 수도 있음을 명시!
// 불필요한것 아니냐는 견해
// 예외를 던질 가능성이 있는 함수
{
cout << "last " << endl;
cout << "throws exception" << endl;
throw -1; // 다음부분 실행하지 않고 throw
cout << "end last " << endl;
}
void third()
{
cout << "third" << endl;
last(); // 다음부분 실행하지 않고 throw
cout << "end third" << endl;
}
void second()
{
cout << "second" << endl;
try
{
third();
}
catch (double) // throw는 int로 되었는데 double로 밖에 catch하지 못한다면 계속해서 날아간다
{
cerr << "second caught double exception" << endl;
}
cout << "end second " << endl;
}
void first()
{
cout << "first" << endl;
try
{
second();
}
catch (int) // catch!
{
cerr << "first caught int exception" << endl;
}
cout << "end first" << endl;
}
int main(void)
{
cout << "start" << endl;
try
{
first();
}
catch (int)
{
cerr << "main caught int exception" << endl;
// clog
}
// uncaught exceptions 못잡는 오류가 발생하는 경우
catch (...) // catch-all handlers
{
cerr << "main caught ellipses exception" << endl;
}
cout << "end main" << endl;
return (0);
}
예외 클래스 상속 시 catch
문에서 객체잘림과 유사한 현상이 발생할 수 있다. 이를 방지하는 방법과 rethrow
에 대해 알아보자.
#include <iostream>
using namespace std;
class Exception
{
public:
void report()
{
cerr << "Exception report" << endl;
}
};
class ArrayException : public Exception
{
public:
void report()
{
cerr << "Array exception" << endl;
}
};
class MyArray
{
private:
int m_data[5];
public:
int &operator [] (const int &index)
{
if (index < 0 || index >= 5) throw ArrayException();
return (m_data[index]);
}
};
void doSomething()
{
MyArray my_array;
try
{
my_array[100];
}
catch (const int &x)
{
cerr << "exception" << x << endl;
}
catch (ArrayException &e)
{
e.report();
throw e; // rethrow
// throw; // 객체 잘림 발생하지 않음
}
catch (Exception &e)
// catch (Exception &e)이 먼저 작성되어 있다면
// 받는 쪽에서 ArrayException이 아닌 Exception으로 받기 때문에
// 객체잘림과 유사하게 Exception report 출력
{
e.report();
}
}
int main(void)
{
try
{
doSomething();
}
catch(ArrayException &e)
{
cout << "main()" << endl; // rethrow 한것을 받는다
e.report();
}
return (0);
}
14.4 std::exception 소개
다양한 경우에 대한 예외처리가 std::exception
을 통해 이미 구현되어 있다. 이를 활용하는 방법에 대해 알아보자.
#include <iostream>
#include <exception> // <-
#include <string>
class CustomException : public std::exception
{
public:
const char *what() const noexcept override
{
return ("Custom exception");
}
};
int main(void)
{
try
{
throw std::runtime_error("Bad thing happend");
}
catch (std::length_error &exception)
{
std::cerr << exception.what() << std::endl;
}
catch (std::exception &exception)
{
std::cerr << exception.what() << std::endl;
}
return (0);
}
14.5 함수 try
#include <iostream>
using namespace std;
class A
{
private:
int m_x;
public:
A(int x) : m_x(x)
{
if (x <= 0)
throw 1;
}
B(int x) try : A(x)
{
// do init
}
catch (...)
{
cout << "catch in B constructor " << endl;
// throw; // 없어도 있는것처럼 작동!
}
};
class B : public A
{
public:
B (int x)
: A(x) // init
{
}
};
void doSomething()
{
try
{
throw - 1;
}
catch (...)
{
cout << "catch in doSomething()" << endl;
}
}
int main(void)
{
try
{
// doSomething()
B b(0);
}
catch (...)
{
cout << "catch in main(void)" << endl;
}
return (0);
}
14.6 예외처리의 위험성과 단점
- 소멸자 안에서
throw
는 금기시 된다. → runtime error!
- 스마트 포인터를 사용하게 되면 영역을 벗어나게 되었을때(
throw
) 자동으로 메모리를 해제한다.
#include <iostream>
#include <memory>
using namespace std;
class A
{
public:
~A()
{
throw "error"; // <-
}
};
int main(void)
{
try
{
int *i = new int[10000000];
unique_ptr<int> up_i(i); // <-
// do something with i
throw "error";
// delete[] i;
// A a;
}
catch (...)
{
cout << "catch" << endl;
}
return (0);
}
Author And Source
이 문제에 관하여([따배C++] 14. 예외처리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@24siefil/따배C-14.-예외처리
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
#include <iostream>
using namespace std;
class A
{
private:
int m_x;
public:
A(int x) : m_x(x)
{
if (x <= 0)
throw 1;
}
B(int x) try : A(x)
{
// do init
}
catch (...)
{
cout << "catch in B constructor " << endl;
// throw; // 없어도 있는것처럼 작동!
}
};
class B : public A
{
public:
B (int x)
: A(x) // init
{
}
};
void doSomething()
{
try
{
throw - 1;
}
catch (...)
{
cout << "catch in doSomething()" << endl;
}
}
int main(void)
{
try
{
// doSomething()
B b(0);
}
catch (...)
{
cout << "catch in main(void)" << endl;
}
return (0);
}
- 소멸자 안에서
throw
는 금기시 된다. → runtime error! - 스마트 포인터를 사용하게 되면 영역을 벗어나게 되었을때(
throw
) 자동으로 메모리를 해제한다.
#include <iostream>
#include <memory>
using namespace std;
class A
{
public:
~A()
{
throw "error"; // <-
}
};
int main(void)
{
try
{
int *i = new int[10000000];
unique_ptr<int> up_i(i); // <-
// do something with i
throw "error";
// delete[] i;
// A a;
}
catch (...)
{
cout << "catch" << endl;
}
return (0);
}
Author And Source
이 문제에 관하여([따배C++] 14. 예외처리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@24siefil/따배C-14.-예외처리저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)