MyFunc라는 함수를 호출했는데, 그 안에서 throw절이 실행되면서 예외가 발생했다. 그런데 이 함수내에는 예외처리를 위한 try~catch 문이 존재하지 않는다.

그렇다면 이 상황에서 발생한 예외는 어떻게 처리될까?


-> 이러한 경우 예외처리에 대한 책임은 MyFunc를 호출한 영역으로 넘어가게 된다.



위 예제의 divide 함수 내에서는, 매개변수 num2의 값이 0인 경우 예외가 발생하는데, 이 위치를 감싸는 try~catch 문은 존재하지 않는다. 이런 경우 Divide 함수를 호출한 21행의 위치로 예외 데이터가 전달된다. 

물론 예외 데이터가 전달되었으니, 예외처리에 대한 책임도 함께 넘어간다. 따라서 21행을 감싸는 try~catch문에 의해서 예외가 처리된다. 


결론 : 예외가 처리되지 않으면, 예외가 발생한 함수를 호출한 영역으로 예외 데이터가(더불어 예외처리에 대한 책임까지) 전달된다.






예외상황이 발생한 위치와 예외상황을 처리해야 하는 위치가 다른경우의 예제.



예외의 발생과 처리에 대한 가장 일반적인 모델을 보여준다.


이 예제로 알 수 있는 점: 함수 내에서 함수를 호출한 영역으로 예외 데이터를 전달하면, 해당 함수는 더 이상 실행되지 않고 종료가 된다.

즉, 함수 내에서 예외 데이터를 전달하면, return 문의 실행을 통한 함수의 종료와 마찬가지로 함수를 완전히 빠져 나오는 꼴이 된다.






스택 풀기(Stack Unwinding)


- 예외가 처리되지 않아서, 함수를 호출한 영역으로 예외 데이터가 전달되는 현상을 가리켜 '스택 풀기' 라고 한다.



위 예제는 예외가 발생할 수밖에 없다. 함수 호출 순서는 이렇다.

main -> one -> two -> thr


그리고 thr함수에선 무조건 예외를 발생시킨다. 그런데 이 예외를 처리하기 위한 try~catch 문이 main 함수에 정의되어 있어서 main으로 예외 데이터가 전달된다. 


이렇듯 예외가 처리될 때까지, 호출된 함수의 역순으로 예외 데이터가 전달된다. 그리하여 결국 예외는 thr함수에서 발생했지만, 예외의 처리는 main 함수에서 이뤄지는 형태가 된다.

그런데 예외 데이터가 전달되면, 예외 데이터를 전달한 함수는 종료되기 때문에, 예외 데이터를 전달한 함수의 스택이 반환되는 것은 당연하다. 그래서 예외 데이터의 전달을 가리켜 '스택 풀기(스택의 반환)'라고 하는 것이다. 


※ 만약 main 함수에 try~catch 문을 삭제하면... 즉, 예외상황이 발생했는데 이를 처리하지 않으면 어떻게 될까?

- 예외가 처리되지 않아서, 예외 데이터가 main 함수에까지 도달했는데, main 함수에서조차 예외를 처리하지 않으면, terminate 함수(프로그램을 종료시키는 함수) 가 호출되면서 프로그램이 종료되어 버린다.


'Programming > C++' 카테고리의 다른 글

예외상황을 표현하는 예외클래스의 설계  (0) 2012.10.24
하나의 try 블록과 다수의 catch 블록  (0) 2012.10.24
예외처리(Exception Handling)  (0) 2012.10.17
템플릿과 static  (0) 2012.10.17
템플릿 인자  (0) 2012.10.16
Posted by scii
:

C++에서 말하는 '예외(Exception)' 는 프로그램의 실행 도중에 발생하는 문제상황을 의미한다.

따라서 컴파일 시 발생하는 문법적인 에러는 예외의 범주에 포함되지 않는다.


ex) 나이를 입력하는데 0보다 작은 값이 입력되었다.

       나눗셈을 위한 두 개의 정수를 입력 받는데, 제수로 0이 입력되었다.

       주민등록번호 13자리만 입력하라고 했더니, 중간에 -를 포함하여 14자리를 입력하였다.


이렇듯 '예외' 라는 것은 문법적인 오류가 아닌, 프로그램의 논리에 맞지 않는 상황을 의미한다.



0으로 나누는 연산은 불가능하므로, 프로그램이 강제로 종료되어버린다.


예외가 발생하면, 그에 따른 처리가 이뤄져야지, 위의 실행결과에서 보이듯이 그냥 프로그램이 종료되어버리는 상황을 만들어서는 안 된다.






if 문을 이용한 예외의 처리




if문을 이용한 예외처리는 "에외처리를 위한 코드와 프로그램의 흐름을 구성하는 코드를 쉽게 구분하지 못하게 한다."


※ if문이 등장하면 에외처리를 위한 코드라고 생각하고, 주석을 달 수 있다.

하지만! 프로그램의 논리적인 기능의 완성을 위해서도 if문은 사용된다. 그리고 예외가 아닌 다른 정보의 기록을 위해서도 주석은 사용된다.

즉, if문과 주석만을 사용해서는 딱 보고 예외처리라고 판단할 수 없다.






C++ 의 예외처리 메커니즘


- C++ 은 구조적으로 예외를 처리할 수 있는 메커니즘을 제공한다. 이 메커니즘을 이용하면, 코드의 가독성과 유지보수성을 높일 수 있다. 

예외의 처리를 프로그램의 일반적인 흐름에서 독립시키는 것이 가능하기 때문이다.


try          예외를 발견

catch         예외를 잡는다.

throw        예외를 던진다.




try 블록

- try 블록은 예외발생에 대한 검사의 범위를 지정할 때 사용된다. 즉, try 블록 내에서 예외가 발생하면, 이는 C++의 예외처리 메커니즘에 의해서 처리가 된다.


try

{

// 예외발생 예상지역 

}


catch 블록

- catch 블록은 try 블록에서 발생한 예외를 처리하는 코드가 담기는 영역으로써, 그 형태가 마치 반환형 없는 함수와 유사하다.


catch(처리할 예외의 종류 명시)

{

// 예외처리 코드의 삽입

}


throw

- 키워드 throw는 예외가 발생했음을 알리는 문장의 구성에 사용된다.

- ex) throw expn;

expn은 변수, 상수 그리고 객체 등 표현 가능한 모든 데이터가 될 수 있으나, 예외상황에 대한 정보를 담은, 의미 있는 데이터이어야 한다. 그래서 위 문장에서 expn의 위치에 오는 데이터를 가리켜 그냥 '예외'라고 표현하기도 한다.


※ try와 catch는 하나의 문장이다. 따라서 항상 이어서 등장해야 한다.

따라서, try 블록 내에서 발생하는 예외는 이어서 등장하는 catch 블록에 의해 처리된다.


=> throw에 의해 던져진 '예외 데이터'는, '예외 데이터'를 감싸는 try 블록에 의해서 감지가 되어 이어서 등장하는 catch 블록에 의해 처리된다.



즉, 예외가 발생하면(throw 절이 실행되면), 프로그램의 흐름이 중지되고, catch 블록에 의해서 예외의 처리과정을 거치게 되는데 이것이 바로 C++ 의 예외처리 메커니즘이다.




try 블록 내에서 예외가 발생하면, catch 블록이 실행되고 나서, 예외가 발생한 지점 이후를 실행하는 것이 아니라, catch 블록의 이후가 실행됨을 보인다.

이렇듯, 예외가 발생하면, 예외가 발생한 지점 이후의 나머지 try 영역은 그냥 건너뛰게 된다.


그리고 throw절에 의해 던져진 예외 데이터의 자료형과 catch 블록의 매개변수 자료형은 일치해야 한다. 만약 일치하지 않으면, 던져진 예외 데이터는 catch 블록으로 전달되지 않는다.






try 블록을 묶는 기준


- try 블록을 만나면 그 안에 삽입된 문장이 순서대로 실행된다.

- try 블록 내에서 예외가 발생하지 않으면 catch 블록 이후를 실행한다.

- try 블록 내에서 예외가 발생하면, 예외가 발생한 지점 이후의 나머지 try 영역은 건너뛴다.


묶는 기준 : 예외가 발생할만한 영역만 묶는 게 아니라, 그와 관련된 모든 문장을 함께 묶어서 이를 하나의 '일(work)' 의 단위로 구성하는 것이다.


"try 블록 내에서 예외가 발생하면, 예외가 발생한 지점 이후의 나머지 try영역은 건너뛴다."

Posted by scii
:

템플릿과 static

Programming/C++ 2012. 10. 17. 01:06 |

- 함수 템플릿과 static지역변수 -


static 지역변수는 템플릿 함수 별로 각각 존재하게 된다.



실행결과로 알 수 있듯이, 컴파일러에 의해서 만들어진 템플릿 함수 별로 static 지역변수가 유지됨을 보이고 있다.






- 클래스 템플릿과 static 멤버변수 -


static 멤버변수는 변수가 선언된 클래스의 객체간 공유가 가능한 변수이다.

템플릿 클래스 별로 static 멤버변수를 유지하게 된다.



32~33행: 10과 15를 더하고 있다, 그래서 25가 출력.


36~37행: 26행에서 정의한 static 특수화로 인하여 mem이 5로 초기화되고 거기에 100이 더해져서 105가 출력된다.


언제 template <typename T> 를 쓰고 언제 template <> 를 쓰는가?


"템플릿 관련 정의에는 template <typename T> 또는 template <> 와 같은 선언을 둬서, 템플릿의 일부 또는 전부를 정의하고 있다는 사실을 컴파일러에게 알려야 한다."


template <typename T>

class Simple

{

public:

T SimpleFunc(T num) { ... }

};

이 경우에는 템플릿의 정의에 T가 등장하므로 template <typename T> 의 선언을 통해서, T가 의미하는 바를 알려야 한다. 




template <>

class Simple<int>

{

public:

int SimpleFunc(int num) { ... }

};

이 정의의 핵심은 <int>이다. 그런데 이 역시 템플릿 관련 정의이기 때문에, 이러한 사실을 알리기 위한 선언이 필요하다. 

하지만 이 정의에서는 T라는 문자가 등장하지 않으니, template <> 을 선언하는 것이다. 


즉, 정의 부분에 T가 존재하면 T에 대한 설명을 위해서 <typename T> 의 형태로 덧붙이면 되고, T가 존재하지 않으면 <>의 형태로 간단하게 선언하면 된다.





- 템플릿 static 멤버변수 초기화의 특수화 -


특수화는 함수 템플릿 또는 클래스 템플릿만을 대상으로 진행할 수 있는 것이 아니다.

클래스 템플릿 정의의 일부인 초기화문을 대상으로도 진행이 가능하다. 방법도 간단하다. 다양한 특수화와 마찬가지로 T를 대신해서 특수화하고자 하는 자료형의 이름을 삽입하면 된다. 


template <>

long SimpleStaticMember<long>::mem = 5;

Posted by scii
:

템플릿 인자

Programming/C++ 2012. 10. 16. 23:42 |

템플릿을 정의할 때 결정되지 않은 자료형을 의미하는 용도로 사용되는 T 또는 T1, T2와 같은 문자를 가리켜 '템플릿 매개변수' 라 한다.

그리고 템플릿 매개변수에 전달되는 자료형 정보를 가리켜 '템플릿 인자' 라 한다.


템플릿 매개변수에는 변수의 선언이 올 수 있다.


아래의 예제를 보면, 템플릿 매개변수의 선언에 마치 함수처럼 변수의 선언이 등장했다.

 

SimpleArray<int, 5> i5arr;

SimpleArray<double, 7> d7arr;


위의 두 문장에서 템플릿 매개변수 len에 전달된 인자 5와 7은 해당 템플릿 클래스에서 상수처럼 사용된다. 

즉, len은 각각 5, 7로 치환되어, 컴파일러에 의해 SimpleArray<int, 5>, SimpleArray(double, 7> 형 템플릿 클래스가 각각 생성된다.


※ 물론 생성자를 이용해도 충분히 구현 가능하다. 그리고 이것이 더 현실적이고, 좋은 방법임에도 틀림이 없다. 



이 예제에서 주목할 사실

-> SimpleArray<int, 5>와 SimpleArray<int, 7> 은 서로 다른 형(type)이다.

ex) i5arr1 = i7arr1;        //컴파일 error!


이렇듯, 템플릿 매개변수에 값을 전달받을 수 있는 변수를 선언하면, 변수에 전달되는 상수를 통해서 서로 다른 형의 클래스가 생성되게 할 수 있다. 


따라서 위 예제의 경우, 길이가 다른 두 배열 객체간의 대입 및 복사에 대한 부분을 신경 쓰지 않아도 된다. 자료형도 같고 길이도 같은 배열 객체에 대해서만 대입 및 복사가 허용되니 말이다. 



※ 만약에 생성자를 이용해서 배열의 길이를 결정하게 했다면, 길이가 같은 배열에 대해서는 대입을 허용하기 위해서 추가적인 코드의 삽입이 불가피하며, 이러한 추가적인 코드는 대입 및 복사의 과정에서 CPU가 수행해야 할 일을 늘리는 결과로 이어진다.






템플릿 매개변수는 디폴트 값 지정도 가능하다.


-> 함수의 매개변수에 디폴트 값의 지정이 가능하듯이, 템플릿 매개변수에도 디폴트 값의 지정이 가능하다.



T에 int가, len에 7이 디폴트 값으로 지정되었다.


※ 위 예제에서 보이듯이 템플릿 매개변수에 디폴트 값이 지정되어도, 템플릿 클래스의 객체생성을 의마하는 <> 기호는 반드시 추가되어야 한다. 비록 그안을 비워둘지라도!!

Posted by scii
:

template <class T1>

class MySimple<T1, int>    { ... }


-> T2 하나에 대해서만 부분적으로 특수화를 진행한 것이다. 그래서 이를 가리켜 '클래스 템플릿의 부분 특수화' 라 한다.



MySimple<char, double> obj1;

이 문장에서 <T1, double>에 대해 부분적으로 특수화된 클래스 객체가 생성되었다.


MySimple<int, double> obj3;

이 문장에서 <int, double>에 대해 전체적으로 특수화된 클래스의 객체가 생성되었다.


이렇듯 실행결과를 통해서, 부분 특수화와 전체 특수화의 두 가지 모두에 해당하는 객체생성 문장에서는 전체 특수화된 클래스를 대상으로 객체가 생성됨을 확인할 수 있다.

따라서, 전체 특수화가 부분 특수화보다 우선시 된다고 정리하면 된다.!!!

Posted by scii
:

※ 클래스 템플릿의 특수화 방법 및 개념은 함수 템플릿과 매우 유사하다.


클래스 템플릿을 특수화 하는 이유?

- 특정 자료형을 기반으로 생성된 객체에 대해, 구분이 되는 다른 행동양식을 적용하기 위해서이다.

즉, 클래스 템플릿을 특수화하면, 템플릿을 구성하는 멤버함수의 일부 또는 전부를 다르게 행동하도록 정의할 수 있다.



Posted by scii
:

Point<int>, Point<double> 과 같은 템플릿 클래스의 자료형을 대상으로도 템플릿이 아닌 일반함수의 정의가 가능하고, 클래스 템플릿 내에서 이러한 함수를 대상으로 friend 선언도 가능하다.




24행: 이 함수는 템플릿 클래스인 Point<int> 의 객체 둘을 인자로 받고 반환하는 일반 함수이다.

Posted by scii
:

Template 2

Programming/C++ 2012. 10. 14. 20:17 |

※ C++ 표준 라이브러리는 템플릿을 기반으로 디자인된다. 따라서 템플릿을 잘 알면, 그 만큼 라이브러리에 대한 이해도와 활용능력이 향상된다.


클래스 템플릿을 기반으로 Point<int> 템플릿 클래스의 객체를 저장할 수 있는 객체는 어떻게 생성해야 할까?


BoundCheckArray<int> iarr(50);

-> 다음과 같이 객체를 생성하면, int형 데이터의 저장이 가능한 것처럼, 저장대상의 자료형이 Point<int>이니, 다음과 같이 객체를 생성하면 된다.


BoundCheckArray<Point<int>> oarr(50);


그리고 저장대상이 Point<int>형이 포인터라면,


BoundCheckArray<Point<int>*> oparr(50); 이렇게 선언하면 된다.


또한, 위의 문장은 typedef 선언을 통해 다음과 같이 구성해서 된다.


typedef Point<int>*    POINT_PTR;

BoundCheckArray<POINT_PTR> oparr(50);







템플릿 클래스라 하여 일반 클래스와 비교해서 다른 문법체계를 지니는 것은 아니다. 

우리가 알고 있는 C++ 문법의 이해를 기반으로 템플릿과 관련된 다양한 확장이 가능하다.

Posted by scii
: