C++, 14. 예외처리

이도현·2023년 11월 7일
0

1. 예외처리의 기본

  • try, catch, throw
int main()
{
	double x;
	cin >> x;

	try
	{
		if(x < 0.0) throw std::string("Negative input")
		
		cout << std::sqrt(x) << endl;
	}
	catch(std::string error_message)
	{
		// do something to respond
		cout << error_message << endl;

	return 0;
}

2. 스택 되감기

  • 예외가 발생하면, C++ 런타임은 catch 블록을 찾기 위해 스택을 되감습니다. 이 과정에서 생성된 객체의 소멸자가 호출되어 자원이 정리됩니다.
  • 아래 코드를 통해 작동 순서를 확인할 수 있다.
int main()
{
	cout << "Start" << endl;

	try
	{
		first();
	}
	catch (int)
	{
		cerr << "main caught int exception" << endl;
	}
	uncaught exceptions

	catch(...) // catch-all handlers
	{
			cerr << "main caught ellipses exception" << endl;
	}

	cout << "End main" << endl;

	return 0;
}

void first()
{
	cout << "first" << endl;

	try
	{
		second();
	}
	catch (int)
	{
		cerr << "first caught int exception" << endl;
	}
	
	cout << "End first" << endl;
}

void second()
{
	cout << "second" << endl;

	try
	{
		third();
	}
	catch (double)
	{
		cerr << "second caught int exception" << endl;
	}
	
	cout << "End second" << endl;
}

void third()
{
	cout << "Third" << endl;

	last();

	cout << "End third" << endl;
}

void last()
{
	cout << "last " << endl;
	cout << "Throws exception" << endl;

	throw - 1;

	cout << "End last" << endl;
}

// void last() throw(int) exception specifier
// void last() throw(...) exception specifier

3. 예외 클래스와 상속

  • 사용자 정의 예외 클래스를 만들어 특정한 유형의 예외를 표현.
  • 클래스들은 일반적으로 exception클래스로부터 상속받음
class Exception
{
public:
	void report()
	{
		cerr << "Exception report" << endl;
	}
};

class ArrayException : public Exceoption // 그냥 상속받으면 객체잘림이 일어난다.
{
public:
	void report()
	{
		cerr << "Array exception" << endl;
	}
};
	
class MyArray
{
private:
	int m_data[5];

public:
	... 
};

void doSomething()
{
	MyArray my_array;

	try
	{
		...
	}
	catch (const int & x)
	{
		...
	}
	catch (ArrayExceoption & e)
	{
		...
	}
	catch(Exception & e)
	{
		...
		e.report();
	}
}

int main()
{
	try
	{
		doSomething();
	}
	catch(ArrayExceoption & e)
	{
		cout << "main()" << endl;
		e.report();
	}

	return 0;
}

4. std::exception

  • 모든 표준 예외 크랠스의 기본 클래스
#include <exception>

class CustomException : public std::exception // 이 친구도 main() try에 넣으면 Custom Exception이 출력된다.
{
public:
	const char * what() const noexception override
	{
		return "Custom exception";
	}
};

5. 함수 try

  • 생성자와 소멸자에서 자주 사용됨
  • 초기화 목록에서 발생하는 예외를 처리하는데 유용
class A
{
private:
	int m_x;
public:
	A(int x) : m_x(x)
	{
		if(x <= 0)
			throw 1;
	}
};

class B : public A
{
public:
	//B(int x) 기본적 사용
	//	: A(x)
	//{}

	B(int x) try : A(x) // initalize 과정에서 try 하고싶을 때 사용
	{
		//do intialization
	}
	catch (...)
	{
		cout << "Catch in B constructor " << endl;
		//throw 없지만 있는 것 처럼 작동한다.
	}
};

int main();
{
	try
	{
		B b(0);
	}
	catch(...)
	{
		cout << "Catch in main()" << endl;
	}

	return 0;
}

6. 예외처리의 위험성과 단점

1) 메모리 누수가 날 수 있다.

#include <meomory> // 해결방법
int main()
{
	try
	{
		int *i = new int[1000000];
		unique_ptr<int> up_i(i); //스마트포인터로서 다음 강의에서 더 자세히 다룬다.

		// do something with i
		throw "error";

		//delete[] i; // throw로 error 을 던지면 delete는 실행되지 않으며 메모리 누수 발생
		//스마트포인터를 사용해 delete이 필요 없어짐.
	}
	catch(...)
	{
		cout << "Catch" << endl;
	}

	return 0;
}

2) 주의할점: 소멸자에선 exception을 throw 할 수 없다
3) for문 안에 try catch throw는 속도를 현저히 느리게한다.
4) 모든 것에 예외처리를 넣는 것은 권장되지 않는다.

profile
좋은 지식 나누어요

0개의 댓글