読者です 読者をやめる 読者になる 読者になる

継承とstd::shared_ptr & unique_ptrとカスタムデリータ

C++

ふと、継承されたクラスとスマポのカスタムデリータについて気になったので調べてみた

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:スマポのカスタムデリータ

Log for Backup - Naoki_Rinの学習

この辺みて

 

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という関数があるらしい