次はカスタムデリータやアロケータを受け取るバージョンの コンストラクタ を実装してみます.(だんだんソース全部載せるのも長ったらしく感じてきたの で,今回は追加変更する部分だけコードを載せることにします)
まずカスタムデリータを渡す場合だと delete
してるところを置き換えれ
ばいいので,こんな感じに shared_count
を派生すれば良さそうです.
template <typename T, typename D> struct shared_count_with_deleter :public shared_count { D deleter_; shared_count_with_deleter(D d) :deleter_(d) {} virtual void release(void* p) const { deleter_(reinterpret_cast<T*>(p)); } };
コンストラクタはこんな感じ.
template<typename Y, typename D> shared_ptr(Y * p, D d) :ptr_(p), count_(new shared_count_with_deleter<Y, D>(d)) { }
次にカスタムアロケータを渡す場合を考えてみます.やることは
shared_count
の生成破棄をアロケータ経由で行うようにすればいいという
ことなので,コンストラクタの実装はカスタムアロケータで確保したメモリ
に対して placement new で shared_count
を生成します.
template<typename Y, typename D, typename A> shared_ptr(Y * p, D d, A a) :ptr_(p), count_(0) { typedef shared_count_with_deleter_allocator<Y, D, A> sc_type; typename A::template rebind<sc_type>::other a2(a); count_ = a2.allocate(1); new (static_cast<void*>(count_)) sc_type(d, a); }
placement new によって生成さたので shared_count
側で自分自身を破棄
するのに delete
演算子は使えません.というわけで自分自身を破棄する
処理をカスタム化するために destroy
メソッドを追加します.
struct shared_count { long count_; shared_count() :count_(1) {} virtual ~shared_count() {} void increment() { ++count_; } void decrement(void* p) { if (--count_ == 0) { release(p); destroy(); } } virtual void destroy() { delete this; } virtual void release(void*) const = 0; };
そしてアロケータ利用版の shared_count_with_deleter_allocator
では
destroy
で明示的にデストラクタを呼び,アロケータ経由でメモリを開放
するようにします.
template <typename T, typename D, typename A> struct shared_count_with_deleter_allocator :public shared_count { D deleter_; A allocator_; typedef shared_count_with_deleter_allocator<T,D,A> this_type; shared_count_with_deleter_allocator(D d, A a) :deleter_(d), allocator_(a) {} virtual void release(void* p) const { deleter_(reinterpret_cast<T*>(p)); } virtual void destroy() { typedef typename A::template rebind<this_type>::other A2; A2 a(allocator_); this->~this_type(); a.deallocate(this, 1); } };
いちおうちゃんと動いてるかなー?
0 件のコメント:
コメントを投稿