OSDN Git Service

utakataの標準となる例外クラス及びマクロを定義した。
[simplecms/utakata.git] / src / common / smart_ptr.h
1 // 参照カウンタによるスマートポインタを提供します。
2 //
3 // ここで定義されるスマートポインタは、scoped_ptrとは異なり、
4 // 最終的に参照しているデータが、解体責任を負う点で異なります。
5 // 最終的に参照しているデータを判定するため、参照カウンタ形式で
6 // 解体責任を移譲していきます。
7 //
8 // また、このスマートポインタは配列を扱うことができます。
9 //
10 // example
11 // -------
12 // smart_ptr<CHoge> h(new CHoge());
13 //
14 // smart_ptr<CHoge> ha();
15 // h.add(new CHuga);
16
17 #ifndef _UTAKATA_SRC_COMMON_SMART_PTR_H_
18 #define _UTAKATA_SRC_COMMON_SMART_PTR_H_
19
20 #include "src/common/ref_delete.h"
21
22 namespace utility {
23
24 template<class T> class smart_ptr {
25  public:
26   template<class S> explicit
27   smart_ptr(S* p, bool owner = true, ref_delete_base* ref = NULL) :
28       obj_(NULL),ref_obj_(NULL) {
29     if (p != NULL) {
30       init(p,owner, ref);
31     }
32   }
33
34   //デフォルトコンストラクタ
35   smart_ptr() : obj_(NULL),ref_obj_(NULL) {}
36
37   //コピーコンストラクタ
38   smart_ptr(const smart_ptr<T>& p) :
39       obj_(NULL),ref_obj_(NULL) {
40     //参照カウントを増やしつつ、コピー。
41     inc(p);
42   }
43
44   // 自分にコピーされる前に、前のオブジェクトの参照カウントを
45   // 減らしておく。
46   smart_ptr<T>& operator=(const smart_ptr<T>& obj) {
47     dec();
48
49     smart_ptr<T> tmp(obj);
50     swap(tmp);
51     return *this;
52   }
53
54   //参照数を減らすだけ。
55   virtual ~smart_ptr() {dec();}
56
57   //明示的に削除するための構文
58   virtual void release() {dec();}
59
60   //ここからは、ポインタの振りをするための仕掛け。
61   T& operator*() const {return *get();}
62   T* operator->() const {return get();}
63
64   // 同一かどうかをチェックする。
65   bool operator==(const smart_ptr<T>& rh) {
66     return obj_ == rh.obj_;
67   }
68   bool operator!=(const smart_ptr<T>& rh) {
69     return !(*this.obj_ == rh.obj_);
70   }
71
72   // 現在保持しているポインタを明示的に返します。
73   T* get() const {
74     if (ref_obj_ == NULL) {
75       return NULL;
76     }
77
78     return obj_;
79   }
80
81   // 内部で参照しているオブジェクトがNULLであるかどうかを返します。
82   bool is_null() const {
83     return ref_obj_ == NULL && obj_ == NULL;
84   }
85
86   // オブジェクトが単一の場所からのみ参照されているか。
87   bool is_only_ref() const {
88     return ref_obj_->reference() == 1;
89   }
90
91   //=============================================
92   //追加生成関数群
93   //=============================================
94
95   // 渡されたsmart_ptrが格納しているオブジェクトを参照するようにします。
96   // テンプレートパラメータSは、Tの派生クラスである必要があります。
97   template<class S>
98   void upcast(const smart_ptr<S>& p) {
99     if (reinterpret_cast<void*>(this) != reinterpret_cast<void*>(&p)) {
100       dec();
101
102       obj_ = p.object();
103       ref_obj_ = p.ref_obj();
104
105       if (ref_obj_ != NULL) {
106         ref_obj_->inc_ref();
107       }
108     }
109   }
110
111   // 現在保持している型を新規に生成します。新規の生成では、デフォルトコ
112   // ンストラクタが使用されます。
113   void reset() {
114     dec();
115     init(new T, true);
116   }
117
118   // 外部より明示的に新しい管理対象オブジェクトを渡して初期化を行います。
119   // ownerが指定されない場合、デフォルトで管理が行われます。
120   template<class S>
121   void reset(S* object, bool owner = true) {
122     dec();
123     if (object != NULL) {
124       init(object, owner);
125     }
126   }
127
128   // 外部より明示的に新しい管理対象オブジェクトを渡して初期化を行います。
129   // ownerが指定されない場合、デフォルトで管理が行われます。
130   // 削除時には、渡されたdeleterによって処理が行われます。
131   template<class S>
132   void reset(S* _p, ref_delete_base* ref, bool owner = true) {
133     dec();
134     if (_p != NULL && ref != NULL) {
135       init(_p, owner, ref);
136     }
137   }
138
139  private:
140
141   // smart_ptrの初期化処理を行います。ref_delete_baseが指定されている場合
142   // には、渡されたオブジェクトが解体オブジェクトとして利用されます。
143   template<class S>
144   void init(S* _p, bool owner, ref_delete_base* ref = NULL) {
145     obj_ = _p;
146
147     if (ref_obj_ != NULL) {
148       ref_obj_ = NULL;
149     }
150
151     if (ref != NULL) {
152       ref_obj_ = ref;
153     } else if (owner) {
154       ref_obj_ = new ref_noarray_object<S>(_p);
155     } else {
156       ref_obj_ = new ref_null_object<S>(_p);
157     }
158
159     ref_obj_->set_reference(1);
160     ref_obj_->set_maxnum(1);
161     ref_obj_->set_objsize(sizeof(S));
162     ref_obj_->set_owner(owner);
163   }
164
165   // 渡されたsmart_ptrを参照するように変更し、参照数を加算します。
166   void inc(const smart_ptr<T>& p) {
167     ref_obj_ = p.ref_obj_;
168     obj_ = p.obj_;
169     if (ref_obj_ != NULL) {
170       ref_obj_->inc_ref();
171     }
172   }
173
174   void swap(smart_ptr<T>& p) {
175     std::swap(ref_obj_, p.ref_obj_);
176     std::swap(obj_, p.obj_);
177   }
178
179   // 現在自身が参照しているオブジェクトの参照数を減算し、
180   // オブジェクトの参照を初期化します。
181   // 参照数の減算時、参照数がゼロになった場合にのみ、ref_objをdeleteします。
182   void dec() {
183     if (ref_obj_ != NULL) {
184       if (ref_obj_->dec_ref()) {
185         delete ref_obj_;
186       }
187     }
188     ref_obj_ = NULL;
189     obj_ = NULL;
190   }
191
192   //========================================
193   //コピーの際に使用するconst関数群
194   //========================================
195
196   // 現在保持しているデリータを返します。
197   ref_delete_base* ref_obj() const {return ref_obj_;}
198
199   // 現在保持しているオブジェクトを返します
200   T* obj() const {return obj_;}
201
202  private:
203
204   T* obj_;      //保持すべきオブジェクト。参照カウントオブジェクトと同一
205
206   ref_delete_base* ref_obj_;     //参照カウントオブジェクト
207 };
208 }; // end of namespace utility
209
210 #endif /* _UTAKATA_SRC_COMMON_SMART_PTR_H_ */