본문 바로가기

IT책/Effective c++

항목 8 : 예외가 소멸자를 떠나지 못하도록 붙들어 놓자

예외처리는 중요하다. 왜냐?

아주 극단적이지만 예를 들어보겠다.

 

#include 
#include 
using namespace std; 

char* err_log; 

class test  
{

public: 

	int size = 0; 
	~test()  
{ 

	cin >> size; 
	err_log = new char[size]; 

} 

}; 

int _tmain()  
{ 
	test t; 
}

 

만약 프로그램이 돌아가고있는데  그 상태에서 test클래스는 log를 저장해주는 클래스라고 쳐보자

그런데 size입력하는곳에 갑자기 11111111111111이라는 말도안되는 크기를 할당하겠다고 하면은 어떻게 되겠는가? 

당연하지만  인정사정없이 뻗어버린다.

조그만한 에러가 떠서 잠시 log만 저장하러갔는데 아주 운없이 소멸자 부분에서 에러가 나버리면 이렇게 뻗어버린다.

이렇게 되면 안되기때문에 예외처리를 해야한다.어디가 어떻게 에러가 난지 알면은 마음이라도 편한데 어디가 어떻게 잘못된지도 모르면 답이없어진다. 그러니 예외처리는 중요한것같다

 

#include 
#include 
using namespace std; 

char* err; 

class test  
{
public: 

	int size = 0; 
	~test()  
	{ 
		try { 
			cin >> size; 
			err = new char[size]; 
			} catch (bad_alloc& alloc)  
			{ 
				cout << alloc.what() << endl;
			} 

	} 

}; 

int _tmain()  
{ 

	test t; 

}

 

위 코드를 보듯이 예외처리는 의외로 간단하다 소멸자 안에 예외처리를 해주는것이다.

위의 부분은 예외를 먹고 그대로 프로그램을 그대로 실행시키는것이고

바로 아래의 코드는 안정빵으로 무엇이 잘못되서 종료되었는지 알려주고 abort()함수를 이용쓰며 종료시키는 코드이다

 

물론 if와 throw를 써서 상황에 맞게 처리하는것도 있으니 때에 따라서 써보도록하자

 

 

#include
#include
using namespace std;

char* err;

class test 

{public:

int size = 0;
~test() 
{
try {
cin >> size;
err = new char[size];
}
catch (bad_alloc& alloc) 
{
cout << alloc.what() << endl;

abort();
}

}

};

int _tmain() 
{

test t;

}

#include 
#include 
using namespace std; 

char* err; 

class test  
{
public: 

	int size = 0; 
	~test()  
	{ 
		try { 
			cin >> size; 
			err = new char[size]; 
		} 
		catch (bad_alloc& alloc)  
		{ 
			cout << alloc.what() << endl;

			abort();
		} 

	} 

}; 

int _tmain()  
{ 

	test t; 

}

 

그리고 test인터페이스를 잘 설계해서 발생할 소지가 있는 문제에 대처할 기회를 사용자가 가질 수 있도록 하면 어떨까?

함수를 제송하면 이 함수를 실행 중에 발생하는 예외를 사용자가 직접 처리하게끔 말이다

 

 

class test  
{ 
private: 
	enum {OFF,ON}; 
	int flag = 0; 

public: 

	int size = 0; 


	void deleted()  
	{ 
		//가상의 save라는 클래스가 따로 있다고 치자 
		//save.parsing(); 
		flag = ON; 
	} 

	~test()  
	{ 
		if (!flag) {
        
			try { 
				cin >> size; 
				err = new char[size]; 
			} 
			catch (bad_alloc& alloc) 
			{ 
			cout << alloc.what() << endl; 
			abort(); 
			} 
		}
	} 

};

이걸로 끝이다

 

내가 글을 쓰지만 내가 글을 그지같이쓰고 표현을 못한다고 새삼 다시알게되어 가슴이 아프다 하......

쨋든 이걸로 끝이다.

 

 

예외를 일으키는 소멸자는 시한폭탄이나 마찬가지라서 프로그램의 불완전 종료 혹은 미정의 동작의 위험을 내포하고 있기때문에 조심하라고 책에서 써져있다  조심하도록하자 

 

 

이것만은 잊지 말자!

*소멸자에서는 예외가 빠져나가면 안된다. 만약 소멸자 안에서 호출된 함수가 예외를 던질 가능성이 있다면 어떤 예외이든지 소멸자에서 모두 받아낸 후에 삼켜 버리든지 프로그램을 끝내든지 해야 한다

*어떤 클래스의 연산이 진행되다가 던진 예외에 대해 사용자가 반응해야 할 필요가 있다면 해당 연산을 제공하는 함수는 반드시 보통의 함수(즉, 소멸자가 아닌 함수)이어야 한다.