std::tr1::mem_fn
Problem
std::tr1::mem_fnとは、いったい何なのでしょうか?
Solution
次のようなWidgetクラスとコンテナがあるとします。
このような場合に使用するのがstd::mem_fun_refとstd::mem_funです。
まず、コンテナの要素がオブジェクトであるかオブジェクトへのポインタであるかでstd::mem_fun_refとstd::mem_funの2つを使い分けなければなりません。
もっと重大な欠点としては、スマートポインタに対してはどちらも使用できないということです。
Notes
1. Effective STL - 第41項 ptr_fun、mem_fun、およびmem_fun_refの使用理由を理解しよう
std::tr1::mem_fnとは、いったい何なのでしょうか?
Solution
次のようなWidgetクラスとコンテナがあるとします。
class Widget {
public:
...
void test(); // 自己テストを実行する。
...
};
vector<Widget> vw;
list<Widget*> lpw;
コンテナのすべてのWidgetをテストするには、当然のようにstd::for_eachの使用を思いつきます。このような場合に使用するのがstd::mem_fun_refとstd::mem_funです。
#include <vector>
#include <list>
#include <algorithm>
#include <functional>
class Widget {
public:
void test() {}
};
int main()
{
std::vector<Widget> vw;
std::for_each(vw.begin(), vw.end(), std::mem_fun_ref(&Widget::test));
std::list<Widget*> lpw;
std::for_each(lpw.begin(), lpw.end(), std::mem_fun(&Widget::test));
return 0;
}
しかし、このstd::mem_fun_refとstd::mem_funにはいくつか欠点があります。まず、コンテナの要素がオブジェクトであるかオブジェクトへのポインタであるかでstd::mem_fun_refとstd::mem_funの2つを使い分けなければなりません。
もっと重大な欠点としては、スマートポインタに対してはどちらも使用できないということです。
std::list<std::tr1::shared_ptr<Widget> > lspw; std::for_each(lspw.begin(), lspw.end(), std::mem_fun(&Widget::test)); // compile error. std::for_each(lspw.begin(), lspw.end(), std::mem_fun_ref(&Widget::test)); // compile error.そこで、これらの欠点を解消したのがstd::tr1::mem_fnなのです。
#include <vector>
#include <list>
#include <algorithm>
#include <functional>
#include <tr1/memory>
#include <tr1/functional>
class Widget {
public:
void test() {}
};
int main()
{
std::vector<Widget> vw;
std::for_each(vw.begin(), vw.end(), std::tr1::mem_fn(&Widget::test));
std::list<Widget*> lpw;
std::for_each(lpw.begin(), lpw.end(), std::tr1::mem_fn(&Widget::test));
std::list<std::tr1::shared_ptr<Widget> > lspw;
std::for_each(lspw.begin(), lspw.end(), std::tr1::mem_fn(&Widget::test));
return 0;
}
Notes
1. Effective STL - 第41項 ptr_fun、mem_fun、およびmem_fun_refの使用理由を理解しよう
![]() | Effective STL―STLを効果的に使いこなす50の鉄則 スコット メイヤーズ (2002/01) ピアソンエデュケーション この商品の詳細を見る |
ヒープ限定オブジェクト
Problem
あるクラスのインスタンスをヒープオブジェクトに限定したい場合、どのようにすれば良いでしょうか?
Solution
コンストラクタとデストラクタをprivateにして、Creation MethodとDestraction Methodを用意します。
単なるヒープオブジェクトでは面白くないので、今度はスマートポインタに限定してみましょう。
インスタンスをstd::auto_ptrに限定したい場合は、std::auto_ptrをfriendに指定します。
何故なら実際にdeleteを行うのは別のdeleterクラスだからです。
従って、deleterクラスをfriendに指定します。
あるクラスのインスタンスをヒープオブジェクトに限定したい場合、どのようにすれば良いでしょうか?
Solution
コンストラクタとデストラクタをprivateにして、Creation MethodとDestraction Methodを用意します。
class Object {
public:
static Object* createInstance() { return new Object; }
static void destroyInstance(Object* ptr) { delete ptr; }
private:
Object() {}
~Object() {}
};
int main()
{
Object* ptr = Object::createInstance();
Object::destroyInstance(ptr);
return 0;
}
これでヒープオブジェクト以外ではインスタンス化できなくなります。単なるヒープオブジェクトでは面白くないので、今度はスマートポインタに限定してみましょう。
インスタンスをstd::auto_ptrに限定したい場合は、std::auto_ptrをfriendに指定します。
#include <memory>
class Object {
public:
friend class std::auto_ptr<Object>;
static std::auto_ptr<Object> createInstance()
{ return std::auto_ptr<Object>(new Object); }
private:
Object() {}
~Object() {}
};
int main()
{
std::auto_ptr<Object> ptr = Object::createInstance();
return 0;
}
インスタンスをstd::tr1::shared_ptrに限定したい場合は、std::tr1::shared_ptrをfriendに指定しても動きません。何故なら実際にdeleteを行うのは別のdeleterクラスだからです。
従って、deleterクラスをfriendに指定します。
#include <iostream>
#include <tr1/memory>
class Object {
public:
static std::tr1::shared_ptr<Object> createInstance();
private:
Object() {}
~Object() {}
friend struct ObjectDeleter;
};
struct ObjectDeleter {
void operator()(Object* ptr) const { delete ptr; }
};
std::tr1::shared_ptr<Object> Object::createInstance()
{
return std::tr1::shared_ptr<Object>(new Object, ObjectDeleter());
}
int main()
{
std::tr1::shared_ptr<Object> ptr = Object::createInstance();
return 0;
}

