#include <iostream>
using namespace std;
// 예외이야기- 진짜 예외는 객체를(클래스) 만들어서 계층화 해야 한다.
// 예상치 않은 에러가 난다면 설계가 잘못된 것.(사용자가 지정하지 않은 에러)
// 롤백- 예외 발생시 다시 안전된 상태로 돌려놔야 한다.
class Exception {};
class StackException : public Exception {};
class StackUnderflowException : public StackException {};
// 예외 안전성의 개념
// 1. 기본보장: 예외 처리후 메모리등의 리소스낭비는 없지만 프로그램의 상태를 알 
                        수는 없다.
// 2. 강력보장: 예외를 처리한 후 프로그램의 상태가 예외발생 이전으로 복구된다.
// 3. 완전보장: 예외가없다. int a = 10;
// 예외중립( Exception neutral )
// exceptional c++
http://cafe.naver.com/cppmaster/1516
class Test
{
       int buf[100];
public:
       Test() { throw 1; }
};
void main()
{
       try
       {
       Test* p = new Test; // 1. 메모리할당
                           // 2. 생성자호출- 그런데예외가나왔다.
       // (1)에서 할당한 메모리는 해지되었을까?? 낭비인가??
       // new 자체에서 에러 발생시 낭비를 방지하는 코드가 있다. 
       }
       catch( int )
       {
       }
}
void foo() // 어떠한 예외라도 나올 수 있다. 예외가 없다는 throw()를 붙여줘야 한다.
{
       try
       {
             char* p = new char;
       }
       catch( std::bad_alloc e )
       {
             // 어떻게 처리할까?
// 1. 메모리를 재할당해서 성공할 수 있다면 ok.
             // 2. 그렇지 않다면 호출자에게 다시 전달.. - 예외중립
             throw;
       }
}
// 아래 대입 연산자가 예외안전성을 지원하는가?
class String
{
       char* buff;
       int sz;
public:
       String& operator=( const String& s )
       {
             if ( &s == this ) return *this;
             
             char* temp = new char[ s.sz+1 ]; // 예외가 발생 할 수도 있다.
             strcpy( buff, s.buff );
             // 예외가 발생하지 않는 코드(강력보장)는 나중에 수행하자.
             delete[] buff;      // 예외가 없다.
             buff = temp;
             sz = s.sz;          // 예외가 없다.
             return *this;
       }
};
void main()
{
       String s1 = "hello";
       String s2 = "A";
       try
       {
             s1 = s2;
       }
       catch ( ... )
       {
       }
       cout << s1 << endl;   // 'A' 또는'hello" 가나와야한다.
}
class Stack
{
       int buf[10];
       int top;
public:
       int Pop() throw( StackUnderflowException )
       {
             if ( top < 0 )
             {
                    throw StackUnderflowException();
             }
             return buf[--top];
       }
};
void main()
{
       Stack s;
       try
       {
             int n = s.Pop();
       }
       catch( StackUnderflowException e )
       {
             cout << "예외처리" << endl;
       }
       // 예외를 잡아서 문제를 처리했다. 이제 stack을 계속 사용할 수 있을까?
       s.Push(10);
}