언어 자료구조 알고리즘/Escort C++

[C++] 8. 구조화 된 예외처리

언제나휴일 2016. 4. 15. 15:26
반응형

8. 구조화 된 예외처리


 C++ 언어는 탄생 후에 시대 흐름에 맞게 생존하기 위해 새로운 문법들이 계속 추가되었습니다. 이 중의 하나가 namespace이고 또 다른 하나로 구조화된 예외처리가 있습니다. 이 외에도 #pragma 를 비롯하여 여러 종류의 확장자를 가능하게 하는 등의 많은 사항이 추가되었는데 여기에서는 구조화된 예외처리에 대해 살펴보기로 하겠습니다.

 

 구조화된 예외처리는 특정 구문을 수행함에 개발자의 논리적 버그나 사용자의 잘못된 사용으로 인한 오류 외에도 발생하지 말아야 할 특수한 상황으로 더이상 진행하지 못하는 예외 등을 개발 단계에서 빠르게 확인할 수 있고 개발자의 의도에 맞게 해당 상황을 처리하기 위해 생겨났습니다. 어떻게 보면 이미 Java에서 제공되었는 구조화된 예외처리를 C++에서도 제공해야 함을 느껴 제공하게 되었다고 볼 수도 있을 것입니다.

 

 구조화된 예외처리에 대한 문법 사항은 크게 어렵지 않게 되어 있어 사용하는데 크게 어려움은 없습니다. 다만, 실제 개발자가 이를 효과적으로 사용할 수 있는가에 대한 부분은 좀 다를 수 있습니다.

 

먼저, 구조화된 예외처리 구문에 대한 문법적인 사항을 살펴보기로 합시다.

 

 구조화된 예외처리 구문은 크게 예외가 발생할 수도 있는 구문에 대한 시도하는 try 블럭과 예외 상황에 도달했을 때 예외를 발생하는 throw , 발생한 예외를 잡아 처리하는 catch 블럭으로 구성됩니다.

 

 간단한 예를 들기 위해 7장의 [ ] 연산자 중복 정의에서 사용한 IntArr 클래스를 사용하기로 하겠습니다.

 

IntArr.h

#pragma once

class IntArr

{

    int *base;

    const int capa;

public:

    IntArr(int _capa);

    ~IntArr(void);

    int &operator[](int index);

private:

    void Initailize();

    bool AvailIndex(int index);

};

  

IntArr.cpp

#include "IntArr.h"

IntArr::IntArr(int _capa):capa(_capa)

{

    base = new int[capa];

    Initailize();

}

IntArr::~IntArr(void)

{

    delete[] base;

}

int &IntArr::operator[](int index)

{

    if(AvailIndex(index))

    {

        return base[index];

    }

    throw "잘못된 인덱스를 사용하였습니다.";

}

void IntArr::Initailize()

{

    for(int i = 0;i<capa;i++)

    {

        base[i] = 0;

    }

}

bool IntArr::AvailIndex(int index)

{

    return (index>=0)&&(index<capa);

}

 

 위와 같이 구현된 IntArr을 사용하면 사용하는 곳에서 [] 연산을 통해 유효하지 않은 index를 사용한다면 무엇을 반환해 주어야 할까요? 이 같은 경우에 throw문을 사용하여 예외를 발생시킬 수 있습니다. 만약, 사용하는 곳에서 예외에 대해 시도하는 try 블록과 catch 블록이 없다면 프로그램은 비정상적으로 터지게 되어 개발자로 하여금 예외 상황에 도달하였음을 인지하게 합니다.

 

 이처럼 예외를 발생하는 것을 사용하는 곳은 다음과 같이 try 블록과 catch 블록을 통하여 예외를 감지하고 이에 대해 처리를 할 수 있습니다.

 

Example.cpp

#include "IntArr.h"

#include <iostream>

using namespace std;

void main()

{

    try

    {

        IntArr arr(10);

        int i = 20;

        arr[i] = 80;

    }

    catch(const char *msg)

    {

        cout<<msg<<endl;

    }

}

 

 catch 블록은 메서드처럼 보이지만 메서드가 아닙니다. 그리고 하나의 try 블록에 여러 개의 catch 블록이 올 수 있습니다. 이 때 앞쪽에 있는 catch블록에서 예외를 받게 되면 그 뒤에 있는 catch 블록들은 무시됩니다. 예를 들어, ExBase 클래스가 있고 ExDerived 클래스가 ExBase 기반에서 파생된 클래스라고 가정합니다. 이 경우에 catch 블록이 ExBase 개체를 받는 블록이 있고 그 이후에 ExDerived 개체를 받는 블록이 있다면 발생한 예외가 ExBase 개체이든 ExDerived 개체이든 ExBase 개체를 받는 catch 블록만 가동될 것입니다. 기반 클래스 형식의 포인터 변수로 파생된 개체를 관리할 수 있기 때문입니다. 이 같은 경우에는 파생된 개체를 받는 catch 블록부터 기반 클래스 개체를 받는 catch 블록 순으로 구현하면 목적에 맞게 수행될 것입니다


8장  처리

(모든 동영상 강의는 무료입니다.)


반응형