Deleting derived classes in std::unique_ptr<Base> containers

后端 未结 2 609
我寻月下人不归
我寻月下人不归 2021-01-07 05:05

I\'m a little confused. Basically, I\'ve got 2 different resource managers (AudioLibrary and VideoLibrary) that both inherit from a shared BaseLibrary class. This base class

相关标签:
2条回答
  • 2021-01-07 05:10

    This is due to the fact that you haven't declared your Media destructor virtual. As you can see, if you do, for example:

    struct Media {
        virtual ~Media() = default;
    };
    
    struct AudioLibrary : Media {};
    struct VideoLibrary : Media {};
    
    int main() {
        std::map<int, std::unique_ptr<Media>> map;
        map[0] = std::unique_ptr<Media>(new AudioLibrary());
        map[1] = std::unique_ptr<Media>(new VideoLibrary());
    }
    

    demo

    both destructors will be called.

    0 讨论(0)
  • 2021-01-07 05:17

    The default deleter for unique_ptr<T> is the aptly named default_delete<T>. This is a stateless functor that calls delete on its T * argument.

    If you want the correct destructor to be called when a unique_ptr to a base class is destructed, you must either use a virtual destructor, or capture the derived type in a deleter.

    You can do this quite easily using a function pointer deleter and captureless lambda:

    std::unique_ptr<B, void (*)(B *)> pb
        = std::unique_ptr<D, void (*)(B *)>(new D,
            [](B *p){ delete static_cast<D *>(p); });
    

    Of course, this means that you need to add the template argument for your deleter to all uses of unique_ptr. Encapsulating this in another class might be more elegant.

    An alternative to this is to use shared_ptr, as that does capture the derived type, as long as you create the derived shared_ptr using std::shared_ptr<D>(...) or, preferably, std::make_shared<D>(...).

    0 讨论(0)
提交回复
热议问题