Post List

2015년 1월 4일 일요일

예외를 던지지 않는 swap에 대한 지원도 생각해 보자.

* std::swap이 여러분의 타입에 대해 느리게 동작할 여지가 있다면 swap 멤버 함수를 제공합시다. 이 멤버 swap은 예외를 던지지 않도록 만듭시다.

class WidgetImpl { ... }; // 내부Data가 큼

class Widget {
public:
    Widget(const Widget& rhs);
    Widget& operator=(const Widget& rgs) {
        *pImpl = *(rhs.pImpl);
    }
private:
    WidgetImpl* pImpl;
};

위의 예제를 보면 std::swap이 호출되었을 때는 큰 양의 Data가 복사되어야 한다. 하지만 사실상 pImpl의 Pointer만 바꿔줘도 된다. 심하게 비효율적인 swap이라는 말이다.

namesapce std {
    template<>
    void swap<Widget>(Widget& a, Widget& b) {
        swap(a.pImpl, b.pImpl);
    }
}

위와 같이 std::swap을 특수화하면 좋겠지만 pImpl은 private 라서 외부에서 접근이 불가능하다. 그래서 멤버swap 및 비맴버 swap을 모두 제공해줘야 한다.

* 멤버 swap을 제공했으면, 이 멤버를 호출하는 비멤버 swap도 제공합니다. 클래스(템플릿이 아닌)에 대해서는, std::swap도 특수화해 둡시다.

class Widget {
public:
    void swap(Widget& other) {
        using std::swap;
        swap(pImpl, other.pImpl);
    }
};

namesapce std {
    template<>
    void swap<Widget>(Widget& a, Widget& b) {
        a.swap(b);
    }
}



 위의 Code는 정상동작한다. 하지만 Widget이 template으로 되어 있다면 ? C++ Class Template에 대해서는 부분 특수화(Partial Specialization)을 허용하지만 Function Template에 대해서는 허용하지 않도록 정해져 있다. 이럴 경우 swap을 std namespace에 특수화 하지말고, Widget과 같은 namespace에 특수화 하는것은 가능하다.


namespace WidgetStuff {
    template<typename T>
    class Widget { ... };

    template<typename T>
    void swap(Widget<T>&a, Widget<T>& b) { a.swap(b); }
}


 Compiler는 C++의 이름 탐색 규칙[아참, 이 규칙은 인자 기반 탐색(argument-dependent lookup) 혹은 쾨니그 탐색(Koening lookup)이란 이름으로 알려져 있다]에 의해 WidgetStuff namespace 안에서 Widget 특수화 버전을 찾아낸다.

*  사용자 입장에서 swap를 호출할 때는, std::swap에 대한 using 선언을 넣어 준 후에 namespace 한정 없이 swap을 호출합시다.

 그냥 swap을 사용하면 뭐가 호출될까 ?
 1. std에 있는 일반형 버전 (확실히 있음)
 2. std의 일반형을 특수화한 버전 (있을수도 없을수도 있음)
 3. T 타입 전용의 버전 (있을수도 없을수도 있지만, 확실히 std 안에는 없는 것)

template<typename T>
void do(T& a, T&b) {
    using std::swap;
    swap(a, b);
}


위의 Code를 실행하면 위의 3가지 버전을 모두 다 찾도록 시도한다. 만약 std::swap(a,b); 로 호출해버리면 std::swap만 찾고는 나머지는 시도도 하지 않는다.

* 사용자 정의 타입에 대한 std 템플릿을 완전 특수화하는 것은 가능합니다. 그러나 std에 어떤 것이라도 새로 '추가'하려고 들지는 마십시오.

 swap은 예외를 던지지 않도록 만들어야 한다. 왜냐면 위에서 봐서 알겠지만, 강력한 예외 안전성 보장(strong exception-safety guarantee)를 제공하도록 도움을 주는 방법이 있기 때문이다.
 

댓글 없음:

댓글 쓰기