Media Log


1. 예외 처리(Exception Handling)


예외 처리(Exception Handling)에서 예외(Exception)이란 프로그램 실행 도중에 일어나는 비정상적인 상황을 의미합니다. 이런 상황이 벌어질때, 이를 처리하는 과정을 예외 처리라고 합니다. 예를 들어서, 나눗셈 프로그램에서 사용자로부터 두 개의 정수를 입력받는데, 나누는 수를 0으로 입력한것과 같이 말이죠. 직접 그런 프로그램을 만들어 보도록 합시다.

#include <iostream>

using namespace std;

int main()
{
	int a, b;

	cout << "두 개의 정수를 입력하세요: ";
	cin >> a >> b;
	cout << a << "를 " << b << "로 나눈 몫은 " << a/b << "입니다." << endl;
	return 0;
}

결과:

두 개의 정수를 입력하세요: 10 2

10를 2로 나눈 몫은 5입니다.

..

두 개의 정수를 입력하세요: 5 0

계속하려면 아무 키나 누르십시오 . . .


코드를 보시면, 7행에 입력되는 두개의 정수를 담을 a와 b 변수가 선언되어 있습니다. 그리고 10행에서, 사용자로부터 a, b를 입력받고, 11행에서 a를 b로 나누고 난 뒤의 몫을 출력합니다. 결과를 보시면, 10을 2로 나눈다던가, 5를 3으로 나누면 잘 출력이 되지만, 나누는 수를 0으로 두었더니 프로그램이 갑자기 종료되어 버렸습니다. 기존에는, 이런 상황을 아래와 같이 예외를 처리했습니다.

#include <iostream>

using namespace std;

int main()
{
	int a, b;

	cout << "두 개의 정수를 입력하세요: ";
	cin >> a >> b;
	if (b == 0) // 나누는 수가 0이라면,
		cout << "나누는 수가 0이 될 수 없습니다." << endl;
	else
		cout << a << "를 " << b << "로 나눈 몫은 " << a/b << "입니다." << endl;
	return 0;
}

결과:

두 개의 정수를 입력하세요: 10 2

10를 2로 나눈 몫은 5입니다.

..

두 개의 정수를 입력하세요: 4 0

나누는 수가 0이 될 수 없습니다.

계속하려면 아무 키나 누르십시오 . . .


11행을 보시면, b가 0일 경우에 "나누는 수가 0이 될 수 없습니다."를 출력하고 프로그램이 종료됩니다. 반대로, 0이 아닐 경우에는 몫을 사용자에게 보여줍니다. 나누는 수가 0이 입력되어도, 프로그램은 종료되지 않습니다. 이런 방식으로 예외 처리를 하게 되면, 예외가 발생할때마다 이렇게 처리를 해주어야 하기 때문에 똑같은 코드가 늘어나 코드만 차지하거나, 예외 처리의 구분이 명확하지 않습니다. 그럼 어떻게 하여야만 할까요?


바로, 우리가 지금 배우게될 C++의 예외 처리를 이용하면 쉽게 해결할 수 있습니다.


2. try~catch(시도하다~잡다), throw(던지다)


C++에서 제공하는 예외 처리 메커니즘인 try~catch, throw에 대해 알아봅시다. try~catch, throw의 기본 형식은 아래와 같습니다.

try { // 예외가 발생하는 영역
   if (예외 조건) throw 예외 객체; // 예외가 발생하면 예외를 던지는 영역
} catch (예외 객체) { // 던져진 예외를 잡는 영역
   // 예외 처리 영역
}

살펴보자면, 예외가 발생할만한 영역을 try로 감싸주고, 그 뒤에 try 영역 내에서 예외 조건이 만족하면, throw로 그 예외를 던집니다. 그러면 catch가 그 예외를 잡아 처리해줍니다. 그리고, catch문이 굳이 하나가 아니라 2개 이상 등장해도 됩니다. 던져진 예외 객체와 한번, 위의 나눗셈 예제에서 if문이 아닌 try~catch, throw를 이용한 방법으로 예외 처리를 구현해보도록 하겠습니다.

#include <iostream>

using namespace std;

int main()
{
	int a, b;

	cout << "두 개의 정수를 입력하세요: ";
	cin >> a >> b;

	try {
		if (b == 0) throw b;
		cout << a << "를 " << b << "로 나눈 몫은 " << a/b << "입니다." << endl;
	} catch (int exception) {
		cout << "예외 발생, 나누는 수는 " << b << "가 될 수 없습니다." << endl;
	}
	return 0;
}

결과:

두 개의 정수를 입력하세요: 5 0

예외 발생, 나누는 수는 0가 될 수 없습니다.

계속하려면 아무 키나 누르십시오 . . .


코드를 살펴보시면, 12~17행에서 try~catch 구문이 사용되었습니다. 사용자가 10행에서 a와 b값을 입력하게 하고나서, try 영역 안으로 진입합니다. 13행에서, 만약 b가 0이면(나누는 수가 0이면), 이 b를 throw를 이용해 예외를 던져버립니다. 그럼 이렇게 던져진 예외는, 예외 데이터인 exception에 b의 값이 들어가게 되며, catch가 잡아 처리하게 됩니다.


만약, 예외가 발생하지 않으면 catch 영역은 실행되지 않습니다. 이번엔, 함수 내에서 예외가 발생하였을 경우 그 예외를 처리하도록 해봅시다.


3. 함수 예외 처리(Function Exception Handling)


이름이 func인, 두개의 정수를 인자로 받는 함수를 정의해봅시다. 그리고 그 함수 내에 b가 0이면(나누는 수가 0이면) 예외를 던지도록 하고, 그 아래 몫을 출력하도록 해봅시다. 아래처럼, 함수에서 예외가 발생했을 경우에 어떻게 예외가 처리되는지 살펴보도록 합시다.

#include <iostream>

using namespace std;

void func(int a, int b)
{
	if (b == 0) throw b;
	cout << a << "를 " << b << "로 나눈 몫은 " << a/b << "입니다." << endl;
}

int main()
{
	int a, b;

	cout << "두 개의 정수를 입력하세요: ";
	cin >> a >> b;

	try {
		func(a, b);
	} catch (int exception) {
		cout << "예외 발생, 나누는 수는 " << b << "가 될 수 없습니다." << endl;
	}
	return 0;
}

결과:

두 개의 정수를 입력하세요: 4 0

예외 발생, 나누는 수는 0가 될 수 없습니다.

계속하려면 아무 키나 누르십시오 . . .


코드를 보시면, 5~9행에 func란 함수가 정의되었습니다. 함수 내부를 살펴보시면, 전달받은 b의 값이 0일 경우에 예외를 던지고 있습니다. 그런데, func 함수 내에는 예외를 처리하는 영역이 없기 때문에, func 함수가 호출된 영역으로 예외를 전달합니다.


main 함수 내부로 들어가면, 19행에서 try 내에 func 함수가 호출되었는데, func 함수에서 예외가 발생하면, 예외 데이터를 호출 영역으로 다시 전달합니다. 그럼 다시 전달된 예외 데이터를 catch 영역이 잡아 처리하게 되는 것입니다. (참고로, 기본 데이터형(int, char..)뿐만 아니라 객체(Object)도 예외로 던질 수 있습니다.)


4. 스택 풀기(Stack Unwinding)


위와 같이, 예외를 처리하는 영역이 없어 이 예외가 호출된 영역을 타고 계속 전달되는 현상을 가리켜 스택 풀기(Stack Unwinding)이라고 합니다. 아래 예제를 통해, 스택 풀기가 어떤 것인지 확인해보도록 합시다.

#include <iostream>

using namespace std;

void func1() { throw 0; }
void func2() { func1(); }
void func3() { func2(); }
void func4() { func3(); }

int main()
{
	try {
		func4();
	} catch (int exception) {
		cout << "예외 발생, " << exception << "!" << endl;
	}
	return 0;
}

결과:

예외 발생, 0!

계속하려면 아무 키나 누르십시오 . . .


코드를 보시면, 5~8행에서 func1부터 func4까지 함수가 정의되었습니다. func1에서 예외 데이터를 던지며, func2 함수는 func1 함수 호출을, func3 함수는 func2 함수 호출을, func4 함수는 func3 함수를 호출합니다. main 함수 내의 13행을 보시게 되면, func4 함수가 호출되었습니다. 그러면 아래와 같이, func1 함수까지 호출하겠죠? 함수의 호출 순서는 아래와 같을 것입니다.


func4() -> func3() -> func2() -> func1()


그럼, 예외 데이터는 어떻게 넘어갈까요? 아래를 한번 보도록 합시다.


<스택 메모리(Stack Memory)>


func4() 호출 -> func3() 호출 -> func2() 호출 -> func1() 호출 -> func1 함수 내에서 예외 데이터 던짐 -> func2 함수가 예외 데이터를 받고 다시 func3 함수에 던짐 -> func3 함수가 예외 데이터를 받고 다시 func4 함수로 던짐 -> func4 함수가 예외 데이터를 받고 다시 main 함수 내에 있는 예외 처리 영역으로 던짐 -> 예외 처리


함수가 호출될 때는 저렇게 각 함수의 스택 프레임이 생성됩니다. 그리고, func1 함수에서 throw를 만나고, 자신과 자기를 호출한 함수의 스택을 모두 정리(해제)하고 돌아갑니다. 이것이 스택 풀기(Stack Unwinding)입니다.


이번 강좌는 여기서 마치도록 하겠습니다. 수고하셨고, C++ 강좌는 예외 처리를 마지막으로 끝을 내려 합니다. 나머지 올라오지 않은 강좌는 번외편으로 작성하도록 하겠습니다. 그리고 설명이 부족하다 싶으시면, 덧글로 달아시면 보충 설명을 달아드리도록 하겠습니다.

  1. 이전 댓글 더보기
  2. 허재영 at 2014.12.17 16:59 신고 [edit/del]

    돈내고 들어도 모자랄만한 강의를 올려주시는 분한테
    감사하다는 말은 못할망정 어찌 저런 댓글을 달 생각을 하시는지 참ㅋ
    마음에 안드는 부분이 있을수도 있으나 최소한의 예의는 갖춰야죠
    누가보면 님한테 돈받고 강의 해주시는 줄 알겠네요 ㅋㅋ

    Reply
  3. kims at 2015.01.14 15:09 신고 [edit/del]

    음.. 뭐 필요하신 분들은 소스보기를 이용하시는 방법이 있습니다..

    Reply
  4. SYP at 2015.02.23 11:30 신고 [edit/del]

    C++ 강좌 끝까지 잘 보았습니다.
    전체적으로 조망해 볼수 있어 좋았고 자신감이 생겨 더 많이 공부하고 싶네요.
    감사합니다. 작성자님~!

    Reply
  5. SYP at 2015.02.23 11:30 신고 [edit/del]

    C++ 강좌 끝까지 잘 보았습니다.
    전체적으로 조망해 볼수 있어 좋았고 자신감이 생겨 더 많이 공부하고 싶네요.
    감사합니다. 작성자님~!

    Reply
  6. jiwu at 2015.03.17 18:04 신고 [edit/del]

    좋은 강좌 감사합니다.

    Reply
  7. lillim at 2015.04.23 18:50 신고 [edit/del]

    수고하셨습니다. 다시 공부하는데 빠르게 도움이 됐습니다.

    Reply
  8. SongHee at 2015.11.09 15:07 신고 [edit/del]

    C++ 강의 ㅋㅋ하루만에 달렸는데
    그럼에도 불구하고 글이 쉽게써져 있어서
    이해도를 높이는데 많은 도움 얻었습니다^^ 감사합니다!

    Reply
  9. cvpr at 2016.01.14 13:31 신고 [edit/del]

    덕분에 c++ remind 공부 제대로 하고 갑니다.. ^^

    Reply
  10. 씨뿔뿔 at 2016.02.12 17:41 신고 [edit/del]

    잘배웠습니다~ 제 주위에도 엑시님처럼 잘하시는 분이 계시면 좋겠네요 ㅠㅠ 후속편은 먼미래에 나오겠죠? 바쁘시다보니..

    Reply
  11. 이희동 at 2016.03.06 20:04 신고 [edit/del]

    올려주신 강좌을 두번이나 열공해서 읽었습니다. 매번 읽을 때마다 보는 관점이 조금 달라지고, c와 c++의 기초적인 개념을 다시 한번 일깨워 주셔서 감사의 글을 남깁니다.

    Reply
  12. ryan c at 2016.05.08 19:51 신고 [edit/del]

    정말 훌륭한 분이라 생각됩니다. 젊은 나이에 실력도 출중하시지만 더욱 놀라운 것은, 그 나이에 걸맞지 않게 매우 성숙하시고 강의를 전달하는 능력이 탁월한 것이 인상적이었습니다. 대단히 감사합니다. 건강하시고 복 많이 받으시고, 외국으로 유학가셔서 훌륭한 소질을 크게 크게 기르셨으면 좋겠어요 :)

    Reply
  13. Tyler at 2016.05.16 02:01 신고 [edit/del]

    덕분에 굉장히 쉽고 빠르게 C++를 공부할 수 있었습니다. 많지 않은 분량인데도 핵심만 잘 짚어주셔서 효율적으로 공부할 수 있었네요. 다른 강의들도 읽어보겠습니다. 감사합니다.

    Reply
  14. 장도익 at 2016.08.08 12:12 신고 [edit/del]

    너무나 알기쉽게 설명해주신덕분에 정말로 많은 도움이 됐습니다.
    이제 갓 입문했는데 하루만에 강좌를 마칠 수 있었습니다.
    감사합니다.

    Reply
  15. Zemma at 2016.11.30 05:32 신고 [edit/del]

    정주행했는데 이렇게 쏙쏙 들어오는 강의는 처음입니다.
    학교수업으로 진행하다 보니 강의가 시원찮고 이해하기 어려워 수업 외적인 부분을 많이 찾아 해맸는데 여기서 끝을 보내요.
    이렇게 좋은 강의 만들어 주셔서 정말정말 감사합니다.

    Reply
  16. 지나가던사람 at 2016.12.08 02:54 신고 [edit/del]

    이렇게 프로그래밍 관련 글을 명확하게 잘 쓰시는 분이 있다니... 구글링 하다가 들어와서 글 몇개 보고있는데 감탄이 나올 따름입니다.

    Reply
  17. jane doe at 2017.01.16 16:18 신고 [edit/del]

    감사합니다. 많이 배웠습니다.

    Reply
  18. 꺼삐딴리 at 2017.08.07 17:15 신고 [edit/del]

    감사합니다. 처음부터 끝까지 잘 보고 갑니다.

    Reply
  19. C++ at 2018.01.02 14:44 신고 [edit/del]

    너무너무 감사합니다. 임베디드 개발자를 목표로
    C는 생각한 기능을 어느정도 자유롭게 표현할 정도로 연습이 되었는데,

    C로만 생각하려고 하다보니 C++은 이해가 참 어려워서 포기했었습니다.

    신입으로 취직후, MFC/QT를 하게되어, 공부를 시작했는데...

    이번에 이 강좌를 보고서 다시! 입문하고 이 강좌를 마치고 나니
    C++에 슬슬 자신감이 생기는군요!

    다른 강좌도 열심히 보고 배워가겠습니다!

    Reply
  20. ㅇㅇ at 2018.06.14 19:23 신고 [edit/del]

    좋은 강좌 감사합니다

    그 어떤 책보다도 명쾌하고 초보자가 궁금해할할 것을 깔끔하게 알려주셨네요

    처음부터 끝까지 쉬지 않고 다 공부하게 되었습니다

    Reply
  21. ㅇㅇ at 2018.07.29 04:16 신고 [edit/del]

    감사합니다. C/C++ 정독했는데, 정말 전달력 뛰어나시네요..

    Reply

submit

티스토리 툴바