[C++] 예외처리(try ~ catch, throw) 사용법


Study/C , C++ , MFC  2020. 4. 4. 01:50

안녕하세요. 명월입니다.


이 글은 C++에서 예외처리(try ~ catch, throw) 사용법에 대한 글입니다.


C++에서의 예외 처리는 엄청 단순합니다. 오히려 Java와 C#등의 다른 언어 때문에 헤갈립니다.

일단 C#의 예외처리와 비교를 하겠습니다. (다른 언어도 비슷합니다.)

링크 - [C# 강좌 - 21] 예외 처리


먼저 C#과 가장 다른 특징은 c++은 finally가 없습니다. try ~ catch만 있습니다. 그렇기 때문에 finally로 메모리나 리소스 반환이 안됩니다.

#include <stdio.h>
#include <iostream>
using namespace std;
// Node 클래스
class Node
{
// 접근 제한자 설정 - 내부 참조 전용
private:
  // data 값 선언
  const char* data = "hello world";
public:
  // 값 취득
  const char* getData()
  {
    return data;
  }
};
// Node의 값을 취득하는 함수
const char* getData()
{
  // try ~ finally의 구문은 c++에서 존재하지 않는다.
  try
  {
    // Node 클래스의 메모리 할당
    Node* node = new Node();
    // data값 취득 리턴
    return node->getData();
  }
  finally
  {
    // return하고 나서 메모리 해제
    delete node;
  }
}
// 실행 함수
int main()
{
  // 메모리 취득
  const char* data = getData();
  // 콘솔 출력
  cout << data << endl;
  return 0;
}

node에서 값을 할당하고 finally에서 메모리 해제를 하고 싶은데 finally가 없다고 에러가 나옵니다.

그래서 조금 소스를 귀찮게 해제하고 리턴하는 방식으로 작성해야 합니다.

위처럼 작성 해야 합니다. 사실 C/C++에서 finally가 없었는데 Java, C#에서 생긴 것이겠습니다. 저도 C/C++를 오랫만에 정리하다보니 글을 쓰면서 알았네요.. C/C++은 finally가 없었습니다...

C/C++할 때는 몰랐다가 Java와 C#을 주로 사용하는 현재는 finally가 없으니깐 불편하기도 하고 엄청 이상하네요...


두번째는 throw가 되지 않는 예외 처리는 잡을 수 없습니다. 즉, Java나 C#은 에러가 발생하면 무조록 try ~ catch로 날라갑니다만, c++는 null이라고 해도 throw를 던지지 않으면 그냥 runtime에러가 발생합니다.

#include <stdio.h>
#include <iostream>
using namespace std;
// Node 클래스
class Node
{
// 접근 제한자 설정 - 내부 참조 전용
private:
  // data 값 선언
  const char* data = "hello world";
public:
  // 출력 함수
  void print()
  {
    // 콘솔 출력
    cout << data << endl;
  }
};
// 실행 함수
int main()
{
  try
  {
    // Node 클래스의 메모리 할당
    Node* node = new Node();
    // 메모리 삭제
    delete node;
    // print()함수 호출.. 그러나 메모리가 삭제되었기 때문에.. data값에서 에러가 발생..
    node->print();
  }
  catch (...)
  {
    // 에러가 발생하면 catch함
    cout << "catch" << endl;
  }
  return 0;
}

여기까지 보면 Java나 C#을 생각하면 null 에러가 발생해서 catch에 잡힐 것 같습니다.

분명 에러가 발생했는데 try ~ catch에 잡히지 않습니다. 이게 다른 것입니다.

#include <stdio.h>
#include <iostream>
using namespace std;
// Node 클래스
class Node
{
// 접근 제한자 설정 - 내부 참조 전용
private:
  // data 값 선언
  const char* data = "hello world";
public:
  // 출력 함수
  void print()
  {
    // 에러 발생.
    throw 100;
    // 콘솔 출력
    cout << data << endl;
  }
};
// 실행 함수
int main()
{
  // Node 변수 선언
  Node* node;
  try
  {
    // Node 클래스의 메모리 할당
    node = new Node();
    // print()함수 호출
    node->print();
  }
  // throw가 int형일 경우.
  catch (int e)
  {
    // 에러가 발생하면 catch
    // 콘솔 출력
    cout << "error code " << e << endl;
  }
  // 메모리 삭제
  delete node;
  
  return 0;
}

이번에는 print함수 안에서 throw int을 날렸습니다. catch(int)로 그 throw를 받았습니다.


if else와 try ~ catch는 비슷한 형태를 가집니다. 구조적으로 보면 try ~ catch가 더 좋아보입니다. 호출되는 하위 함수에서도 throw만 날리면 catch가 있는 곳으로 포인터가 이동하니깐 말입니다.

그러나 try ~ catch는 if else와 다르게 throw를 날리면 overhead가 발생하기 때문에 성능에 저하가 발생합니다. 그래서 최대한 if else로 걸러주는게 중요합니다. 그러나 문제는 if else로만 작성을 한다면 로직은 엄청 지저분해지고 복잡해 질 것입니다.

사양에 따라 if else 분기가 자주 발생하고 if 대비 else가 50:50이라면 당연히 if else를 써야 하지만, 분기의 대비가 99 : 1 이라면, 즉, 대부분 if안의 처리가 실행되고 간혹 else 문이 발생한다고 한다면 try catch throw도 고려해 볼 만한 사항입니다.


여기까지 C++에서 예외처리(try ~ catch, throw) 사용법에 대한 글이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.