[Effective C++] 항목 29 : 예외 안전성이 확보되는 그날 위해 싸우고 또 싸우자!

수민이슈·2023년 4월 20일
0

Effective C++

목록 보기
29/30
post-thumbnail

스콧 마이어스의 Effective C++을 읽고 개인 공부 목적으로 요약 작성한 글입니다!

💡 예외 안전성을 갖춘 함수는 실행 중 예외가 발생되더라도 자원을 누출시키지 않으며,
자료구조를 더럽힌 채로 내버려 두지 않는다.
이런 함수들이 제공할 수 있는 예외 안전성 보장은 기본적인 보장, 강력한 보장, 예외 금지 보장이 있다.
💡 강력한 예외 안정성 보장은 '복사-후-맞바꾸기' 방법을 써서 구현할 수 있지만,
모든 함수에 대해 강력한 보장이 실용적인 것은 아니다.
💡 어떤 함수가 제공하는 예외 안전성 보장의 강도는, 그 함수가 내부적으로 호출하는 함수들이 제공하는 가장 약한 보장을 넘지 않는다.


🖊️ 예외 안전성의 동작 원칙

1) 자원을 새게 하지 않는다

lock와 unlock 사이, new와 delete 사이에 위치한 함수가 예외를 발생시키면
unlock, delete가 호출되지 않으면서 자원이 줄줄 샐 수 있다.
이걸 허용하지 않아야 예외 안전성을 가진 함수다!

이걸 해결하려면 너무 쉽다
이젠.. 진짜 익숙하다
스마트 포인터를 사용하자

std::unique_ptr
std::tr1::shared_ptr
std::auto_ptr

2) 자료구조가 더렵혀지는 것을 허용하지 않는다.

코드 구조에 따라, 객체를 수정하다 중간에 이상한 결과가 나온다.
예를들어, 기존 것 삭제 - 새로운 객체 생성 이런 식으로 하면 새로운 객체 생성 시 오류가 발생되면 삭제된 채로 그냥 멀뚱멀뚱... 남는다. 이상한 채로...


🖊️ 예외 안전성을 가진 함수가 제공하는 세 가지 보장

1) 기본적인 보장

함수 동작 중 예외 발생 시, 자원을 새도록 하진 않겠다.
모든 객체의 상태는 내부적으로 일관성을 유지하고 있다.
그치만 프로그램의 상태가 정확히 어떠한지는 알 수 없다.

2) 강력한 보장

함수 동작 중 예외 발생 시, 프로그램의 상태를 변경하지 않는다.
성공 or 실패. 중간은 없다.

3) 예외불가 보장

이 함수는 절대로 예외를 던지지 않는다.
뭘 했든 절대 예외 안나오고, 동작을 끝까지 잘 수행한다.



뭘 했던 간에,, 어쨌든 예외는 보장해야 될 거 아니니..?
당연히 예외불가 보장이 제일 안전하겠지만,, 현실적으로 사용하긴 힘들겠다.
(기본제공 타입에 대한 연산을 제외하고는 예외를 던지지 않기는 현실적으로 힘들긴 하다.
당장 메모리를 동적으로 할당하려고 해도 메모리가 없으면 예외를 던지니까..)

그래서 현실적으로 기본적인 보장이나 강력한 보장을 선택하게 된다.
강력한 보장이 좀 더 안전하니 이걸 살펴보면,
자원 관리 전담 포인터 (스마트 포인터 등)를 사용해서 메모리 누수를 막고,
복사-후-맞바꾸기(copy-and-swap) 방법으로 구현하면 굿이다.

복사 후 맞바꾸기(copy-and-swap)

객체를 수정할 때,
객체의 사본을 만들고,
사본에다가 수정하고,
다 완료되면 사본과 원본 객체를 맞바꾸면 된다.

예외로부터 겁나 안전하다.
근데 이제,,
사본, 교환에 대한 메모리와 시간이 필요하니...
실용성이 확보될 때만 하자..

물론 이렇게 해도,,
A함수 안에서 B, C함수를 부른다고 치자

void A()
{
	...
	B();
    C();
    ...
}

만약에 C 함수가 예외 안전성을 보장하지 않는다면,
당연히 A 함수도 예외 안전성을 보장할 수 없다.
너무나 당연한 일이다..
A에서 C를 호출하니껜,,,


😊

내가 여태까지 해왔던 코딩에서,,
사실 예외 안전성을 크게 생각하진 않았던 것 같다.
그치만
이제는
달라달라져야해,, ㅠ,ㅠ

0개의 댓글