std::tr1::mem_fn

Problem
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の鉄則 Effective STL―STLを効果的に使いこなす50の鉄則
スコット メイヤーズ (2002/01)
ピアソンエデュケーション
この商品の詳細を見る

人気blogランキングへ にほんブログ村 IT技術ブログへ FC2ブログランキングへ

ヒープ限定オブジェクト

Problem
あるクラスのインスタンスをヒープオブジェクトに限定したい場合、どのようにすれば良いでしょうか?

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;
}

人気blogランキングへ にほんブログ村 IT技術ブログへ FC2ブログランキングへ

« 前頁へ移動する  | HOME |  次頁へ移動する »

ブログ内検索


このサイト内ウェブ全体
この検索は「緑のgoo」を利用しています

カテゴリー

未分類 (0)
C++ (24)
Books (11)
Bookmarks (1)

最近のエントリ

移植性の高いコードを書くためには (02/16)
ハッシュコンテナ - Part3 (01/10)
ハッシュコンテナ - Part2 (10/29)
日本語によるC++0xに関する記事 (10/23)
foreach (08/03)

Books

C++
プログラミング
デザインパターン
オブジェクト指向

RSSフィード

最新記事のRSS
最新コメントのRSS
最新トラックバックのRSS

アーカイブ

2008年02月 (1)
2008年01月 (1)
2007年10月 (2)
2007年08月 (1)
2007年07月 (2)
2007年06月 (1)
2007年05月 (2)
2007年04月 (1)
2007年03月 (2)
2007年02月 (2)
2007年01月 (3)
2006年12月 (4)
2006年11月 (8)
2006年10月 (6)

連絡先

email.png

Amazon