Effective C++ Item 25 ― 2009年08月11日 02時26分34秒
- スワップ関数は std::swap として提供されている。
- もし、メンバ関数の swap を提供するのであれば、非メンバ関数の swap も準備する事。 さらにクラスの場合は std::swap も特殊化する。しかしクラステンプレートの場合は特殊化は出来ない。
- swap 関数を呼ぶときには using std を関数内で使い std::swap も 名前空間を指定しないでも呼べるようにする。
- 専用の swap 関数を作るのは構わないが、他の副作用を追加しないこと。
一般的なスワップ関数の実装として以下の例をあげている。
namespace std { template<typename T> void swap(T& a, T&anp; b) { T temp(a); a = b; b = temp; } }
この形のスワップ関数を効率良くするためには、クラスを実装の為のクラスと、実装を指すメンバ変数のみの本体の二つに分ける。
これにより、ポインタ一つの入れ換えになるので、動作が軽くなる。class WidgetImpl { private: int a, b, c; std::vector<double> v; } class Widget { private: WidgetImpl *pImpl; }
特殊化の技法を基にして、Widget クラスの swap を作ることが出来る。
メンバ関数のスワップ関数を作り、非メンバ関数から呼び出す。class Widget { public: void swap(Widget& other) { using std::swap; swap(pImpl, other.pImpl); } } namespace std { template<> void swap<Widget>(Widget& a, Widget& b) { a.swap(b); } }
std 名前空間は特殊で新しいテンプレート、クラス、関数などを入れる事は出来ない。その為、このクラスがクラステンプレートであった場合はこの様な特殊化は出来ない。そこで、swap 関数を std 名前空間に入れることはしないが、クラステンプレートと同じ名前空間内に非メンバ関数を用意する。 書式は以下の様になる。
クラステンプレートでは、実行時に一番適した関数が呼ばれる様に手助けをする必要がある。namespace WidgetStuff { template<typename T> class Widget { void swap(Widget<T>& other); }; template<typename T> void swap(Widget<T>& a, Widget<T&t;& b) { a.swap(b); } }
C++ の機構により、obj1 と obj2 に適した型の関数が探される。もし、特殊化された swap 関数があれば、それが呼ばれる。 もし、特殊化 swap 関数が無い時には std から呼ばれるようにtemplate<typename T> void doSomething(T& obj1, T& obj2) { using std::swap; swap(obj1, obj2); }
using std::swap
を入れる。std::swap
の形で呼ぶと、特殊化 swap 関数が呼ばれなくなってしまう。
最近のコメント