62
14예외 처리 모임: 아꿈사 이재정

Tcpl 14장 예외처리

  • Upload
    -

  • View
    731

  • Download
    8

Embed Size (px)

DESCRIPTION

the c++ programming language book 14 chapter presentation

Citation preview

Page 1: Tcpl 14장 예외처리

14장 예외 처리모임: 아꿈사이재정

Page 2: Tcpl 14장 예외처리

목차

목차 있으면 좋겠지만~ 내용이 너무 많군요.

Page 3: Tcpl 14장 예외처리

에러를 처리하는 일반적인 방식들

1. 프로그램을 종료하거나2. 에러를 나타내는 값을 반환하거나3. 정상적인 값을 반환하고 비정상적인 상태로 프로그램을 끝내든가, 아니면

4. 에러의 경우에 호출되도록 만들어 둔 함수를 호출한다.

Page 4: Tcpl 14장 예외처리

C++ 예외 처리

C++의 예외 처리 메커니즘은 종래의 에러 처리 기법이 불충분하고, 깔끔하지 않으며, 높은 에러 발생률을 보이는 경우에 종래의 기법 대신에 쓸 수 있는 기능이다.

Page 5: Tcpl 14장 예외처리

C++ 예외 처리

에러 처리용 코드와 '정상 실행용' 코드가 별도의 영역에서 서로 끼어들지 않고 공존하고 있는 구조이기 때문에 코드 읽기가 더 쉬울 뿐 아니라 개발 도구로 고치기도 쉽다.

Page 6: Tcpl 14장 예외처리

C++ 예외 처리의 거추장스러움

Page 7: Tcpl 14장 예외처리

C++ 예외 처리가 거추장스러운가?

프로그램에 예외가 사용되면 예외 처리 코드가 도드라지게 복잡해 보이긴 한다. 그러나 예외가 사용되었기 때문에 복잡해지는 것은 절대로 아니다. 패전 소식을 가져온 애꿎은 전령에게 침 튀기지 말라는 이야기다. (스트룹형님)

Page 8: Tcpl 14장 예외처리

예외 처리는 이렇게 바라보자

'지금껏 한 번도 생기지 않다가 갑자기 터진것''끔찍한 것'

이것보다 예외는 이렇게 보는 것이 더 정확하다.

'시스템의 특정 부분에 어떤 요청이 들어왔는데 거기서 그것을 처리할 수 없는 경우'

Page 9: Tcpl 14장 예외처리

예외 처리 코드를 익히자

1. 예외 처리는 주로 클래스로 만들어지고, 클래스로 던진다. (throw 된다.)

2. 클래스라서 상속도 가능하다.3. 다형성을 구현할 수 있다. 4. 예외 클래스라고 해서 항상 exception 을 상속받을 필요는 없다.

5. 던진(throw) 것을 받는(catch) 코드는 일반적인 함수 인자 처리 메커니즘과 동일하다.

Page 10: Tcpl 14장 예외처리

파생된 예외 클래스

Page 11: Tcpl 14장 예외처리

예외 처리 클래스의 복사 손실

Page 12: Tcpl 14장 예외처리

복사 손실을 막는 법은 레퍼런스로

Page 13: Tcpl 14장 예외처리

복합 예외

하나 이상의 예외를 하나로 묶어 통합하는 기술이다.

Page 14: Tcpl 14장 예외처리

복합 예외 예제

Page 15: Tcpl 14장 예외처리

복합 예외 결과

Page 16: Tcpl 14장 예외처리

예외 받아 내기 조건

throw E();catch (H) {...}

1. H와 E가 같은 타입이어야 한다.2. H로부터 public 상속으로 파생된클래스가 E어야 한다.3. H와 E가 포인터 타입이고, H와 E가 가리키는 실제 객체의 타입들이 1, 2 조건을 만족

4. H가 참조자 타입이고, H가 참조하는 실제 객채의 타입이 1 혹은 2 조건을 만족한다.

Page 17: Tcpl 14장 예외처리

예외 받아 내기 예제

Page 18: Tcpl 14장 예외처리

예외 받아 내기 결과

Page 19: Tcpl 14장 예외처리

다른 예제

Page 20: Tcpl 14장 예외처리

예외 재전송 (예외 전파)

catch 한 예외를 다시 throw 할 수 있다.재 throw 된 예외는 본래의 타입으로 던져진다.

예외가 던져질 때 객체 복사가 일어난다고 하는데, 테스트 결과 레퍼런스로 던질 때는 복사가 일어 나지 않았다.

Page 21: Tcpl 14장 예외처리
Page 22: Tcpl 14장 예외처리
Page 23: Tcpl 14장 예외처리

예외 처리 전부 받아 내기

try {샬라샬라~

} catch (...) {전부 받아 냅니다.

}

Page 24: Tcpl 14장 예외처리

예외 처리자 블록의 등장순서

try {}catch ( A ) {}catch (...) {}catch ( B ) {

Never reach this code}

Page 25: Tcpl 14장 예외처리

자원 관리

예외 처리와 자원 관리는 무슨 관계일까?

파일이나, 크리티컬섹션, 메모리등을 사용하고 난 이후에 자원을 해제시켜줘야 한다. 이것을 쉽게 처리하기 위해 스마트 포인터와 같은 기술이 쓰인다.

스마트 포인터는 기본적으로 생성자와 소멸자에서 자원을 관리한다.

Page 26: Tcpl 14장 예외처리

자원 관리 방식

생성자와 소멸자는 리턴값이 없기 때문에, 에러 처리 방식이 애매하다.

이 때 예외 처리를 이용하면 간편하다.

생성과 동시에 초기화하는 방식을 "자원획득 즉 초기화" (resource acquisition is initialization)RAII 라고한다.

Page 27: Tcpl 14장 예외처리

파일 리소스 관리

파일은 fopen() 함수로 파일을 열고,fclose() 함수로 파일을 닫는다. 실수로 fopen() 후에 닫는 것을 깜빡할 수 있다. 생성자와 소멸자 시스템을 이용해서 자동으로 열고 닫히는 클래스를 만들어 보자.

Page 28: Tcpl 14장 예외처리

파일 리소스 관리 클래스

Page 29: Tcpl 14장 예외처리

File_ptr 사용 예제

Page 30: Tcpl 14장 예외처리

예외 발생시 소멸자 호출

예외가 발생하면, 해당 유효 범위를 벗어날 때, try 블록 안에 만들어진 지역 객체는 모두 없어진다. (소멸자가 호출된다.)

생성자에서 발생한 예외일 경우, 해당 객체는 소멸자가 호출 되지 않는다.

소멸자에서 예외가 발생하면, 소멸자가 호출되지 않는다.

Page 31: Tcpl 14장 예외처리

스택 풀기

스택 풀기● 예외가 발생했을 때 예외를 처리해 줄 처리자를 찾아 스택을 거슬러 올라가 탐색하는 과정을 말한다.

● 스택 풀기가 일어나면, 지역적으로 생성된 객체는 모두 다 소멸자가 호출된다.

스택 풀기시 소멸자가 호출 될 때, 다시 예외가 발생하면? terminate() 함수가 호출되어 프로그램이 종료된다.

Page 32: Tcpl 14장 예외처리
Page 33: Tcpl 14장 예외처리

생성자,소멸자 조심해야 할 부분

생성자나 소멸자에서 예외가 발생하면, 해당 블록에서 생성된 지역객체가 해제되지 않기 때문에 주의해야 한다.

Page 34: Tcpl 14장 예외처리
Page 35: Tcpl 14장 예외처리

해결법

동적으로 생성되는 변수들은 객체로 관리하자.

std::vector<int> 를 사용하자.

Page 36: Tcpl 14장 예외처리

auto_ptr을 사용한 자원 관리

동적으로 할당된 경우는 어떻게 하나?

예외가 발생될 때, 소멸자가 호출되면서 자원을 해제 시켜줄 객체가 필요하다.

auto_ptr<T> 을 쓰자.

Page 37: Tcpl 14장 예외처리

auto_ptr<T>

생성자에서 포인터를 할당받고, 소멸자가 호출될 때, delete 가 호출된다. 그 뿐이다.~

같은 포인터를 중복해서 참조하면, delete 가 두번 호출되니 문제가 발생한다.

c++11 에서는 unique_ptr<T>을 쓰라고 조언하고 있다.

Page 38: Tcpl 14장 예외처리
Page 39: Tcpl 14장 예외처리

위험천만한 auto_ptr<T>

vector< auto_ptr<Shape> > v;sort( v.begin(), v.end() );

어떻게 될까?

auto_ptr<T> 은 스마트 포인터가 아니다.

Page 40: Tcpl 14장 예외처리
Page 41: Tcpl 14장 예외처리

오버로딩된 new, delete

오버로딩 된 new/delete 오퍼레이터는 어떻게 될까? 문제 없이 잘된다.

컴파일러는 오버로딩 된 new로 할당 받은 객체를 delete 할 때, 동일하게 오버로딩 된 delete 로 호출하게 되어 있다.

vs2008 에서는 new 와 동시에 delete 같이 오버로딩해야 컴파일 에러가 없지만, vs2010부터는 new 나 delete 둘 중 하나만 정의해도 문제가 없다.

Page 42: Tcpl 14장 예외처리
Page 43: Tcpl 14장 예외처리

placement new 에서 소멸자

원칙적으로 placement new 로 할당 받은 객체를 delete 하는 것은 잘 못된 것이다.

auto_ptr<T> 은 소멸자에서 delete p; 명령어가 실행되기 때문에 placement new로 할당 받았다고 하더라도 delete 가 호출된다.

쉽게 얘기하자면, placement new로 생성된 객체는 auto_ptr<T> 를 쓰면 안된다.

Page 44: Tcpl 14장 예외처리
Page 45: Tcpl 14장 예외처리

자원 고갈에 대한 대책

대응방안

1. 실행재개2. 실행종료

자원 할당 코드는 여러개의 추상화층으로 구성하고, 호출되는 층이 호출하는 층의 보조를 받지 못하게 하라.

Page 46: Tcpl 14장 예외처리

멤버 초기화 식에서 예외 처리

A::A(int s) try : x(s){}catch (...){}

Page 47: Tcpl 14장 예외처리
Page 48: Tcpl 14장 예외처리

복사 생성자, 대입 연산자 예외 처리

1. 복사 생성자에서 예외가 발생하면 소멸자가 호출 되지 않는다. 메모리 누수가 발생될 수 있기 때문에 주의해야 한다.

2. 대입 연산자에서 예외가 발생하면 소멸자가 호출된다. 그렇기 때문에 소멸자가 호출되어도 문제 없도록 프로그램되어 있어야 한다.

Page 49: Tcpl 14장 예외처리
Page 50: Tcpl 14장 예외처리
Page 51: Tcpl 14장 예외처리

소멸자 안에서 발생하는 예외

소멸자 안에서 예외가 발생하면, 평소와 다름없이 예외가 발생한다.

그러나, 스택 풀기 중에 예외가 발생하면 std::terminate() 함수가 호출되면서 프로그램이 종료된다.

스택 풀기 중에 소멸자가 호출되는지, 정상적으로 소멸자가 호출되는지 알 수 있다.

Page 52: Tcpl 14장 예외처리
Page 53: Tcpl 14장 예외처리

'에러'가 아닌 예외들

트리를 순회하면서 재귀 함수를 호출할 때, 재귀를 빠져나오는 코드로 throw를 호출할 수도 있다.

빠르긴 하지만, 이상하다.

어지간한 상황이 아니라면 '예외 처리는 에러 처리'라는 자세를 견지했으면 한다. (스트럽)

Page 54: Tcpl 14장 예외처리

예외 지정 기능

특정 함수에서 어떤 예외가 던져지는지 지정 할 수 있다.

Visual Studio 는 nothrow 만 지원하고 있다.

Page 55: Tcpl 14장 예외처리
Page 56: Tcpl 14장 예외처리
Page 57: Tcpl 14장 예외처리

예외 지정이 발생 시키는 것들 요약

지정한 예외가 아닌 다른 예외를 던지면 std::unexpected() 함수가 호출된다.

set_unexpected() 로 핸들러를 설정할 수 있으며, 이 핸들러에서 새 예외 처리를 throw 하면 원하는 예외 처리를 할 수 있다.

Page 58: Tcpl 14장 예외처리

예외 처리 효율

예외 처리를 구현하기 위한 내부 시스템으로 인해 속도가 느려질 수 있지만, 구조적이고, 조직적인 에러 처리가 필요하다면 예외 처리를 사용하는 것이 이득이다.

Page 59: Tcpl 14장 예외처리

표준 예외 처리

표준 예외를 많이 만든 이유는, 이것들을 기반으로 하여 다른 C++ 예외 클래스를 만들라는 배려로 보면 되겠다.

Page 60: Tcpl 14장 예외처리

바른 프로그래밍을 위한 고수의 조언

1. 에러 처리에는 예외를 사용하자.2. 지역적 흐름 제어 구조로도 충분한 곳에는 예외를 사용하지 말 것.3. 자원 관리에는 "자원획득 즉 초기화"(Resource Acquisition is Initialization, RAII) 기법을 사용하자.4. 모든 프로그램에 예외 안전성을 부여할 필요는 없다.5. 불변속성을 유지하는 데도 "자원획득 즉 초기화" 기법 및 예외 처리자를 사용하자.6. try 블록의 사용은 최대한 자제하자, 직접 에러 처리자 코드를 두기 보다는 "자원획득 즉 초기화" 방법을 적극적으로 활용하자.7. 모든 함수에서 모든 가능한 에러를 도맡아 처리할 필요는 없다.8. 생성자가 수행되다 오동작이 나면, 예외를 던져서 이것을 알릴 것.9. 대입 연산 중에 예외를 던지기 전에, 모든 연산자가 유효한 상태에 있도록 하자.10. 소멸자에서는 예외 발생을 피하자.

Page 61: Tcpl 14장 예외처리

바른 프로그래밍을 위한 고수의 조언

11. 모든 예외를 받아 보고하는 코드는 main()에 두도록.12. 에러 처리와 상관 없는 코드와 에러 처리 코드는 격리 시킬 것.13. 생성자에서 예외를 던지려 할 때 미리 생성자에서 자원이 획득된 상태라면, 해당 자원을 모두 해제하자.14. 자원 관리는 단계적으로 진행되도록 하자.15. 주로 사용하게 될 인터페이스에 대해서는 예외 지정 기능을 사용하자.16. new에 의해 할당되었는데 예외 발생으로 인해 해제되지 않은 메모리가 메모리 누수를 일으킨다는 사실을 잊지말자.17. 함수에서 발생할 수 있는 예외는 언젠가 발생할 것이란 가정을 항상 빠뜨리지 말도록.18. 무릇 예외라면 exception 클래스에서 파생되어야 한다는 편견을 버리자.19. 라이브러리는 자신의 판단만으로 바로 프로그램을 끝내 버리게 만들면 안된다. 예외를 발생시켜 라이브러리 호출자에게 판단을 넘기자.20. 라이브러리는 최종 사용자를 염두에 둔 진단 출력 메시지를 만들어서도 안된다. 예외를 발생시켜 호출자에게 판단을 넘기자.21. 예외 처리 전략은 설계 단계에서 세우자.

Page 62: Tcpl 14장 예외처리

수고하셨습니다.