HyeM

More Effective C++ 본문

Programming/C++

More Effective C++

Hailey_HyeM207 2020. 2. 22. 02:58

예외(Exceptions)

서론

항목 9 : 리소스 누수를 피하는 방법의 정공은 소멸자이다

예외처리하지 않은 원래코드

readALA는 호출될 때마다 힙 객체를 새로 생성함

만약 ) pa->processAdoption 예외발생시에는?  (processAdoptions함수는 예외처리를 못하도록 되어있음)

1. 발생한 예외는 processAdoption을 호출한 함수에 전파됨

2. 이때, processAdoptions의 코드는 모두 실행되지 않은채 지나감=> pa는 절대로 delete되지 않음!

=> 이로인해 processAdoptions는 리소스 누수를 일으키는 함수가 됨

 

해결책 1. try-catch블록 이용

try_catch를 이용해 리소스누수피하기

더보기

Q. try-catch문이란?

-예외처리구문

try   //실행될 코드가 들어감

{

    //수행할 코드

}

catch(받아낼예외)

{

    //예외가 발생할 시 실행할 코드

}

throw   //예외가 발생시킬때 사용

단점 . try-catch문으로 쓰면 코드가 복잡해짐 + 중복코드(delete문으로 포인터를 삭제하는)를 반복해서 넣어주어야 함

 

 

해결책 2 . "포인터처럼 동작하는 객체"  auto_ptr이용

 processAdoptions 함수의 스택에 생긴 지역 객체에 대해 항상 실행되어야 하는 delete코드를 소멸자로 옮기면 좋음.

왜냐하면, 지역객체는 어떤 요인(함수복귀/예외발생)이든지 함수가 종료되면 저절로 없어지기 때문이다.

=>auto_ptr 사용하기

auto_ptr의 대략적인 구조

 auto_ptr 클래스는 힙 객체에 대한 포인터를 생성자를 통해 받고, 이 객체를 소멸자를 통해 삭제함.

auto_ptr을 쓰면, 삭제되지 않은 힙 객체에 대해 고민할 필요없고, 예외가 발생했을 때에도 고민할 필요 없음.

auto_ptr를 이용해 리소스누수 피하기

※auto_ptr의 기본아이디어 : 자동으로 해체되어야 하는 리소스를 이 객체에 저장하고, 리소스의 해제를 객체의 소멸자에게 맡긴다

ㄴ 이를 활용한 또 다른 예제

더보기

예제

( 그래픽 유저 인터페이스 애플리케이션에 사용할 함수를 만드는데, 이 함수에서 어떤 정보를 표시하는 윈도우를 생성해야 한다고 가정 )

문제 )) 만약, w에 정보를 표시하는 도중에 예외가 발생하면, w가 핸들로 잡혀있는 그 윈도우는 다른 동적 할당 리소스처럼 해제되지 못한채로 해매게 된다. 

해결책 )) 리소스를 얻어내는 생성자와 해제하는 소멸자를 가진 클래스를 하나 만든다.

WindowHandle 클래스
함수 displayInfo를 수정함

 

 

항목 9의 핵심 내용 "동적 할당 리소스는 객체로 포장하라"

 


항목 10 : 생성자에서는 리소스 누수가 일어나지 않게 하자

BookEntry클래스의 생성자

 

BookEntry클래스의 소멸자

//짚고 넘어갈거 : C++에서는 널 포인터에 delete를 적용하더라도 하등의 문제가 없기 때문에, delete를 수행하기 전에 각 포인터가 널인지 아닌지 점검하는 코드가 없다.

 

예외 발생 가능성이 있는 이유 )) 

1. operator new가 AudioClip객체에 대한 메모리 할당에 실패할 수 있다.

2. AudioClip 생성자 자체에서 예외를 발생시킬 수 있다.

 

예외발생시 문제점))

-> 예외의 원인이 어떻든 간에, BookEntry생성자 안에서 예외가 발생하면, 이 예외는  BookEntry 객체가 생성되는 지점으로 전파됨.

-> 그러면, theAudioClip이 가리키고자 했던 객체를 생성하다가 예외가 발생했다면, theImage가 이미 가리키고 있는 객체는 삭제가 안됨!!  (BookEntry의 소멸자가 절대로 호출되지 않음)

 

//이유,중요한 내용 : C++은 생성과정이 완료된 객체을 안전하게 소멸

 

해결책 )) try_catch 이용

가능한 모든 예외를 받고(catch) 마무리 코드를 실행한 다음, 받은 예외를 다시 발생시켜 이것이 전파되도록 하는 것.

(좌측)catch를 이용해 에외처리한 것 , (우측)은 (좌측)코드에서 중복코드를 뽑아 보조함수를 만들어 호출하게 만든 코드

 

 


여기서 끝내지 않고, BookEntry 클래스를 약간 다르게 설계하면 어떻게 될까?


 

BookEntry클래스를 약간 다르게 설계한다고 가정하자. theImage와 theAudioClip을 상수포인터로 선언한다.

 

예외가 발생하여 theImage가 가리키는 객체가 절대로 소멸되지 않는 일이 일어나지 않게 하는 방법은?

(=예외가 생성자를 떠난 전파되기 전에 마무리 작업코드를 실행시키는 유일한 방법은?)

=> 같은 장소에서 예외를 잡아두는것!

=>theImage와 theAudioClip이 초기화되는 포인터값을 반환하는 private 정적 맴버 함수를 만들어 놓고, 그 함수에 try-catch블록을 넣는 것

 

'Programming > C++' 카테고리의 다른 글

More Effective C++[항목21-24]  (0) 2020.03.16
More Effective C++[항목16-20]  (0) 2020.03.10
More Effective C++[항목14]  (0) 2020.02.26
More Effective C++[항목13]  (0) 2020.02.24
More Effective C++  (0) 2020.02.20
Comments