次はカスタムデリータやアロケータを受け取るバージョンの コンストラクタ
を実装してみます.(だんだんソース全部載せるのも長ったらしく感じてきたの
で,今回は追加変更する部分だけコードを載せることにします)
まずカスタムデリータを渡す場合だと 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);
}
};
いちおうちゃんと動いてるかなー?