継承とstd::shared_ptr & unique_ptrとカスタムデリータ
ふと、継承されたクラスとスマポのカスタムデリータについて気になったので調べてみた
class Super{
public:
virtual void Iam(){ std::cout << "super class"; };
};
class Sub :public Super{public:
void Iam(){ std::cout << "Sub class"; };
};
1:継承されたクラスとスマポ
std::unique_ptr
std::unique_ptr<Sub> sub(new Sub);
std::unique_ptr<Super> unique = std::move(sub);
std::unique_ptr<Super> unique2(new Sub);
unique->Iam(); //Sub class
unique2->Iam(); //Sub class
動く
std::shared_ptr
auto unisub = std::unique_ptr<Sub>(new Sub);
std::shared_ptr<Super> share = std::move(unisub);
std::shared_ptr<Super> share2 = std::make_shared<Sub>();
auto sub=std::make_shared<Sub>();
std::shared_ptr<Super> share3=sub;
std::shared_ptr<Super> share4(new Sub);
share->Iam();
share2->Iam();
share3->Iam();
share4->Iam();
動く動く
2:スマポのカスタムデリータ
この辺みて
3:継承されたクラスのカスタムデリータ
「ふと、継承された子クラスをメモリプールにぶち込もうと思って、スマポを使った実装にしようとするとどうなるんだろう」って時に頻出する
//std::unique_ptr<Super, DelSup> uni = std::unique_ptr<Super, DelSub>();
std::shared_ptr<Super>sup = std::shared_ptr<Sub>(new Sub,DelSub());
sharedの方は問題ないが*1, uniqueの方は通らない。デリータは統一する必要がある。しかし
std::unique_ptr<Super, DelSup> uni = std::unique_ptr<Super, DelSup>();
//↑エラーはないが当然DelSupのデリータが呼ばれる
//std::unique_ptr<Super, DelSub> uni2 = std::unique_ptr<Super, DelSub>();//通らない
と、サブクラス用のカスタムデリータが使えない。
仕方ないので
class Del
{
public:
void operator()(Super*p){ p->del(*this); }
};
こんなデリータを作るも,これビジターパターンである。サブクラスが増えることを考えると不向きであり、こんなのやるならdeleteをオーバーロードする方が地球と精神に優しい
そもそもカスタムデリータと継承を併用することなんてまずまずないけど、もし使うならさっさと諦めよう
*1:make_sharedが使えないという問題はある。allocの方はallocate_sharedという関数があるらしい