일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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
- exception
- resource management class
- implicit conversion
- 영화 리뷰
- 영화
- 예외
- 상속
- lua
- reference
- 참조자
- c++
- 함수 객체
- 암시적 변환
- 티스토리챌린지
- Effective c++
- virtual function
- 루아
- 오블완
- 다형성
- more effective c++
- 반복자
- 게임
- effective stl
- UE4
- operator new
- 언리얼
- 메타테이블
Archives
- Today
- Total
스토리텔링 개발자
[Effective STL] 38. 함수 객체 클래스 값 전달(pass by value) 고려하기 본문
728x90
항목 38. 함수 객체 클래스는 값으로 전달되도록(pass-by-value) 설계하자
매개변수로서의 함수와 함수 객체
- 함수는 포인터 형태로 매개변수로 넘겨진다.
void qsort(void* base, size_t nmemb, size_t size, int (*cmpfcn)(const void*, const void*));
// cmpfcn을 자세히 살펴보면 값으로 전달되고 있음을 알 수 있다.
// 즉, 함수 포인터는 값으로 전달된다.
- STL 함수 객체는 이 함수 포인터를 본떴으므로, 동일하게 값으로 전달된다.
template<typename InputIterator, typename Function>
Function for_each(InputIterator first, InputIterator last, Function f);
// Function은 값 전달 / 값 반환이 이루어짐을 알 수 있다.
- 물론 '반드시' 값으로 전달됨을 보장하진 않는다. 아래처럼 사용할 수 있기 때문이다.
class DoSomething
{
void operator()(int x) { ... }
...
};
using DequeIntIter = deque<int>::iterator;
deque<int> di;
...
DoSomething d;
...
// DoSomething& 을 매개변수로 넘겼기에 참조 전달과 반환으로 동작한다.
for_each<DequeIntIter, DoSomething&>(di.begin(), di.end(), d);
- 하지만, 값으로 전달되는 것을 기본 전제로 깔고 가는 것이 맞다.
함수 객체를 제대로 동작시키는 일은 사용자의 몫
- 이 말의 의미는...
- 복사 동작중의 비용을 줄이기 위해 함수 객체를 최대한 작게 만들자.
- 가상 함수를 없게 구성하여, 함수 객체를 단형성으로 만들자.
- 값 복사는 슬라이스 문제가 발생할 수 있다.
- 물론 위를 완전히 지키는 것은 사실상 비현실적이다.
- 상태 저장을 위해 함수 객체가 비대화될 수밖에 없는 상황들이 발생할 것이다.
- 구현 상속과 동적 바인딩을 포기하고 클래스를 설계하라는 말인데.. 너무나 비효율적이다.
'함수 객체를 값 전달할 것' 규칙을 어기지 않고 잘 동작하는 함수 객체 만들기
- 함수 객체 클래스에 넣고자 하는 데이터나 가상함수를 추출하여 다른 클래스로 옮긴다.
- 그리고 함수 객체 클래스에 그 다른 클래스의 포인터를 삽입한다.
template<typename T>
class BPFC // Big Polymorphic Functor Class(항목 40 참조)
{
private:
// 값이 비대하다.
Widget w;
int x;
...
public:
virtual void operator()(const T& val) const; // 가상함수를 가진다.
...
};
- 이를 pImpl 상용구를 사용하여 아래처럼 바꾼다.
template<typename T>
class BPFCImpl
{
private:
Widget w;
int x;
...
virtual ~BPFCImpl();
virtual void operator()(const T& val) const;
friend class BPFC<T>;
};
template<typename T>
class BPFC
{
private:
BPFCImpl<T>* pImpl; // 값은 pImpl 포인터 뿐이다.
public:
void operator()(const T& val) const // 이제 가상함수가 아니다.
{
pImpl->operator()(val);
}
...
};
- 주의할 점은, 함수 객체 클래스는 객체 복사에도 적절히 동작해야 한다는 것이다.
- 즉, 함수 객체 구성 시엔, BPFC의 복사 생성자를 어떻게 구현하느냐가 관건이다.
728x90
'개발 > Effective STL' 카테고리의 다른 글
[Effective STL] 40. adaptable한 함수 객체(C++98) (0) | 2025.01.08 |
---|---|
[Effective STL] 39. predicate는 순수 함수일 것 (0) | 2025.01.07 |
[Effective STL] 37. 범위 요약(summarize) (0) | 2025.01.02 |
[Effective STL] 36. copy_if (0) | 2024.12.26 |
[Effective STL] 35. 대소문자 구분하지 않는 법 (0) | 2024.12.24 |
Comments