OSDN Git Service

clonable_ptr, to_shared の operator() を変更( weak_ptr が存在した場合に即座に解放されないバグを修正)
authorSubaruG <subaru_g@users.sourceforge.jp>
Wed, 31 Mar 2010 17:13:59 +0000 (02:13 +0900)
committerSubaruG <subaru_g@users.sourceforge.jp>
Wed, 31 Mar 2010 17:13:59 +0000 (02:13 +0900)
gintenlib/clonable_ptr.hpp
gintenlib/to_shared.hpp
tests/to_shared.cc

index 54116d7..d98a1c5 100644 (file)
@@ -339,7 +339,13 @@ namespace gintenlib
       
       // デストラクタで適宜やってくれるので
       // operator() では何も行わない
-      void operator()( T* ) const {}
+      // と思いきや、 weak_ptr を使った場合はデストラクタ呼び出しまで
+      // 時間がかかるので、きっちり operator() で削除しなきゃダメ
+      void operator()( T* )
+      {
+        // count を破棄する
+        clonable_count().swap( count );
+      }
       
      private:
       clonable_count count;
index b3a54e5..dda5087 100644 (file)
 
   機能:
     各種スマートポインタを shared_ptr に変換します。
-    名前空間の自動紹介は行わない事になりました。代わりに using gintenlib::to_shared としてください。
+    名前空間の自動照会は行わない事になりました。代わりに using gintenlib::to_shared としてください。
+  
+  要求:
+    一般の P に対する要求は、以下の通り:
+      element_type を持つ。
+      P::element_type get() const; メンバ関数を持つ。
+      デフォルトコンストラクタを呼び出せる。例外を投げない。
+      copy constructable である。その際、内部に格納されているポインタのアドレスが変化してもいい。
+      swap( p1, p2 ) が例外を投げない。
 
 */
 
@@ -85,7 +93,7 @@ namespace gintenlib
     // これを実行すると、このオブジェクトは NULL に再設定される
     shared_t to_shared()
     {
-      using namespace std;  // for assert()
+      using namespace std;  // for assert, swap
       T* p = pt.get();
       
       // いったん仮の to_shared_holder を使って shared_ptr を作る
@@ -97,7 +105,7 @@ namespace gintenlib
       
       // これは例外を投げない
       to_shared_holder* holder = boost::get_deleter< to_shared_holder >( temp );
-      // 作ったばかりの holder の型が不一致なわけない
+      // 作ったばかりの holder の型が不一致なわけないが、一応チェック
       assert( holder != 0 );
       
       // これも大丈夫
@@ -118,17 +126,15 @@ namespace gintenlib
       return temp;
     }
     
-    // 一番大事なはずの削除関数・・・だが
-    // やってることは特に無し
+    // 削除関数
     typedef void result_type;
-    void operator()( T* target ) throw ()
+    void operator()( T* )
     {
-      // 一応、正しいターゲットを削除しているかどうか、チェックする
-      using namespace std;
-      assert( !pt.get() || pt.get() == target );
+      // ポインタを破棄する
+      Pointer p0;
       
-      // これが呼ばれた後に shared_ptr の働きでこのオブジェクトが破棄され、
-      // 同時に pt の有効期限も切れるので、ここでは何もしない
+      using namespace std;
+      swap( pt, p0 );
     }
     
    private:
index 660ea07..346e33a 100644 (file)
@@ -26,6 +26,7 @@ struct hoge
   }
   
   hoge( const hoge& )
+    : gintenlib::reference_counter<hoge>()
   {
     cout << "hoge::hoge( const hoge& );\n";
   }
@@ -38,11 +39,60 @@ struct hoge
 };
 
 // 適当な俺俺スマートポインタを作る
-template<typename T>
-struct oreore_ptr
-  : gintenlib::pointer_facade< oreore_ptr<T>, T >
+
+// 深いコピーを行っても格納出来ることを示すため、
+// 簡易版 deep_ptr で試してみる( gintenlib::deep_ptr は専用の to_shared が呼ばれるので)
+#include <gintenlib/pointer_facade.hpp>
+#include <boost/scoped_ptr.hpp>
+template< typename T >
+struct my_deep_ptr
+  : gintenlib::pointer_facade< my_deep_ptr<T>, T >
 {
-};
+  // デフォルトコンストラクタ
+  my_deep_ptr() : p() {}
+
+  // ポインタから作るコンストラクタ
+  explicit my_deep_ptr( T* p_ )
+     : p( p_ ) {}
+  
+  // コピーコンストラクタ
+  my_deep_ptr( const my_deep_ptr& src )
+     : p( src.p ? new T( *src.p ) : 0 ) {}
+  
+  // デストラクタ
+  // scoped_ptr() のおかげで何もしなくていい
+  // ~my_deep_ptr(){}
+  
+  // nothrow swap ( for operator= )
+  void swap( my_deep_ptr& other )
+  {
+    p.swap( other.p );
+  }
+  friend void swap( my_deep_ptr& one, my_deep_ptr& another )
+  {
+    one.swap( another );
+  }
+  
+  // 代入演算は copy して swap
+  my_deep_ptr& operator=( const my_deep_ptr& src )
+  {
+    my_deep_ptr( src ).swap( *this );
+    return *this;
+  }
+  
+  void reset( T* p_ = 0 )
+  {
+    my_deep_ptr( p_ ).swap( *this );
+  }
+  
+  // get pointer
+  // これと pointer_facade からいろいろと自動生成
+  T* get() const { return p.get(); }
+  
+ private:
+  boost::scoped_ptr<T> p;
+
+};  // class my_deep_ptr<T>
 
 // 汎用版はまだテストしない。 intrusive, auto をチェック
 int main()
@@ -86,6 +136,22 @@ int main()
     cout << "scope out: p1, p2\n";
   }
   
+  // ユーザ定義クラス
+  {
+    my_deep_ptr<hoge> p1;
+    PRINT_AND_EXECUTE( p1.reset( new hoge() ) );
+    PRINT_EXPR( p1.get() );
+    boost::shared_ptr<hoge> p2;
+    PRINT_AND_EXECUTE( p2 = gintenlib::to_shared(p1) );
+    
+    // ちゃんと深いコピーできているかチェック
+    PRINT_EXPR( p1.get() );
+    PRINT_EXPR( p2.get() );
+    
+    // 抜けます
+    cout << "scope out: p1, p2\n";
+  }
+  
   return 0;
 }