일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
Tags
- Smart Pointer
- effective stl
- resource management class
- 반복자
- operator new
- 티스토리챌린지
- lua
- 암시적 변환
- iterator
- virtual function
- 언리얼
- more effective c++
- 오블완
- std::async
- c++
- 영화 리뷰
- effective modern c++
- 스마트 포인터
- reference
- 영화
- universal reference
- 게임
- 보편 참조
- Effective c++
- implicit conversion
- exception
- 참조자
- 예외
- UE4
- 상속
Archives
- Today
- Total
스토리텔링 개발자
[More Effective C++] 13. catch 매개변수는 참조자 본문
728x90
항목 13. 발생한 예외는 참조자로 받아내자
catch 매개변수를 포인터로(catch-by-pointer)
- 이론 상으로는 포인터로 받는 것이 가장 효율적이어야 한다.(항목 15 참조)
- 객체의 복사 없이도 전달이 이루어지기 때문이다.
class exception { ... };
void someFunction()
{
static exception ex; // 범위를 벗어나도 살리기 위해 static 선언
// exception ex; // 이처럼 선언하기라도 하면 미정의 동작을 유발한다!!
...
throw &ex; // 포인터 객체를 던진다.
...
}
void doSomething()
{
try
{
someFunction();
}
catch(exception* ex) // exception*를 받는다.
{
...
}
}
- 힙 객체를 새로 만들고, 그 객체를 예외로 던지는 방식은 어떨까?
void someFunction()
{
...
throw new exception; // 괜찮은 것 같지만..
// 1. operator new가 예외를 발생시키면 어쩌나?
// 2. 힙에 할당한 메모리는 누가 해제해주나?
...
}
- 예외를 받는 측에서는 모순이 발생한다.
- 힙에 할당한 메모리의 포인터인지 아닌지 알 방도가 없으므로 delete 할지 말지 결정할 수 없다.
- static이나 전역 변수의 포인터에 대해 delete를 하면 큰일이다.
- 또 하나의 문제
catch 매개변수를 값으로(catch-by-value)
- 효율
- 늘 두 번씩 복사되기 때문에 비효율적이다.(항목 12 참조)
- 슬라이스 문제(slicing problem)
- 파생 클래스 객체가 기본 클래스를 받는 catch문에 들어가면?
- 파생 클래스 부분이 잘려나간다.(sliced off)
- 이 문제는 찾아내기 무척 까다롭다.
- 파생 클래스 객체가 기본 클래스를 받는 catch문에 들어가면?
class exception
{
public:
virtual const char* what() throw();
...
};
class runtime_error : public exception { ... };
class Validation_error : public runtime_error
{
public:
virtual const char* what() throw(); // exception의 것을 재정의
...
};
void someFunction()
{
...
if(유효성 검사가 실패한다면)
{
throw Validation_error();
}
...
}
void doSomething()
{
try
{
someFunction();
}
catch(exception ex)
{
cerr << ex.what(); // 슬라이스 문제!!
// exception::what()이 호출된다.
// Validation_error::what()은 절대 호출되지 않는다.
...
}
}
catch 매개변수를 참조자로(catch-by-reference)
- 모든 것이 행복하다.
- 포인터로 받을때와 비교하면,
- 객체 삭제에 대한 고민이 필요 없다.
- C++ 표준 예외를 처리할 수 있다.
- 값으로 받을때와 비교하면,
- 예외 객체는 한 번만 복사된다.
- 슬라이스 문제가 없다.
void someFunction()
{
...
if(유효성 검사 실패 시)
{
throw Validation_error();
}
...
}
void doSomething()
{
try
{
someFunction();
}
catch(exception& ex) // 단지 &를 붙였을 뿐인데..
{
cerr << ex.what(); // Validation_error::what()를 호출한다!!
...
}
}
참조
[Effective C++] 20. const & 전달하기
항목 20. ‘값에 의한 전달’보다는 ‘상수 객체 참조자에 의한 전달’ 방식을 택하는 편이 대개 낫다 값에 의한 전달C++는 함수로부터 객체를 전달받거나 함수에서 객체 전달시 ‘값에 의한
delightlane.tistory.com
728x90
'Effective C++ > More Effective C++' 카테고리의 다른 글
[More Effective C++] 15. 예외 처리 비용 (0) | 2024.08.20 |
---|---|
[More Effective C++] 14. 예외 지정(예외 명세) (0) | 2024.08.19 |
[More Effective C++] 12. 예외 전달 vs 함수 매개변수 전달 (0) | 2024.08.14 |
[More Effective C++] 11. 소멸자 예외 처리 (0) | 2024.08.13 |
[More Effective C++] 10. 생성자 예외 처리 (0) | 2024.08.12 |
Comments