protected destructor with unique_ptr

前端 未结 2 1660
抹茶落季
抹茶落季 2020-12-12 04:28

I am trying to call APIs from a third party library.

There is a trouble when I want to use unique_ptr with a class having protected destructor.

Here is the e

相关标签:
2条回答
  • 2020-12-12 04:53

    Unfortunately, the real way to get rid of this issue is to not derive classes from Parent, and to not manage the lifetime of Parent objects (or any derived classes) using std::unique_ptr<Parent>.

    In other words, you need to redesign your classes.

    The reasons I say this are

    • If someone has gone to the trouble of giving Parent a protected non-virtual destructor, the intent is most likely to avoid having a Parent * which actually points at an instance of a derived class and is released using operator delete. A library designer will not (normally) do this without good reason.
    • Your code can be forced to compile as is (e.g. by making std::default_delete<Parent> a friend of Parent). However, std::default_delete is used by unique_ptr to release the managed object. And it uses operator delete. That gives undefined behaviour if the object being managed by the unique_ptr<Parent> is of a type derived from Parent.

    So, in short, you're working around the intent of (whoever designed) your third party library and, if you force the code to compile anyway, your reward will be undefined behaviour.

    0 讨论(0)
  • 2020-12-12 04:59

    You can make std::default_delete<Parent> a friend of Parent to fix that error. And you may also like to make ~Parent virtual to avoid undefined behaviour when deleteing a derived class through Parent pointer.

    E.g.:

    class Parent { 
        friend class std::default_delete<Parent>;
        // ...
    protected:
        virtual ~Parent();
        // ...
    

    However, Parent design makes it clear that you are not supposed to delete through Parent pointer, this is why the destructor is non-public. Read Virtuality for more details:

    Guideline #4: A base class destructor should be either public and virtual, or protected and nonvirtual.


    You may like to introduce another intermediate base class to solve the issue:

    class Parent { // Comes from a 3rd-party library header.
    protected:
        ~Parent();
    };
    
    struct MyParent : Parent {  // The intermediate base class.
        virtual ~MyParent();
    };
    
    class Derived : public MyParent {};
    
    std::unique_ptr<MyParent> createDerived() {
        return std::unique_ptr<MyParent>(new Derived);
    }
    
    int main() {
        auto p = createDerived();
    }
    
    0 讨论(0)
提交回复
热议问题