简体   繁体   English

多重继承和unique_ptr销毁

[英]Multiple inheritance and unique_ptr destruction

I have the classic (possible problematic) multiple inheritance diamond scheme. 我有经典(可能有问题的)多重继承钻石计划。

  • B inherits A B继承A
  • C inherits A C继承A
  • D inherits C and B D继承C和B.

I want to have a std::vector that can contain either C or D objects so I make it as std::vector<C> which is D 's dad and it works fine. 我想有一个std::vector ,可以包含CD对象,所以我把它作为std::vector<C>这是D的爸爸,它工作正常。

BUT when I use: std::vector<std::unique_ptr<C>> then I have segmentation fault upon the destruction of the vector. 但是,当我使用: std::vector<std::unique_ptr<C>>然后我在向量的破坏时有分段错误。

** glibc detected *** ./a.out: free(): invalid pointer: 0x0000000009948018***

Why is there a difference? 为什么会有区别? To me, even the first implementation is problematic. 对我来说,即使是第一次实施也是有问题的。

Code

#include <string>
#include <vector>
#include <memory>

class A
{
public:
    A() = default;
};

class B : public virtual A
{
public:
    B() = default;
};

class C : public virtual A
{
public:
    C() = default;
};

class D : public B, public C
{
public:
    D() = default;
};


int main()
{
    { // this crashes
    std::vector<std::unique_ptr<C>> v;
    std::unique_ptr<D> s1(new D());
    v.push_back(std::move(s1));
    std::unique_ptr<C> s2(new C());
    v.push_back(std::move(s2));
    }

    { // this is fine
    std::vector<C> v;
    D s1;
    v.push_back(s1);
    C s2;
    v.push_back(s2);
    }

    return 0;
};

You should declare your destructors as virtual. 您应该将析构函数声明为虚拟。 Otherwise, if your class D is deleted using a pointer to C , then the ~C() destructor will be called and essential parts of the cleanup will be missed. 否则,如果使用指向C的指针删除类D ,则将调用~C()析构函数,并且将错过清理的基本部分。

Also note that in your second part (not using the unique_ptr ) you do some object slicing. 另请注意,在第二部分(不使用unique_ptr )中,您可以执行一些对象切片。 It means you are creating a copy of s1 of type D into a new object of class C , hence you can lose the extra information specific to D . 这意味着您正在将类型Ds1副本创建到C类的新对象中,因此您可能会丢失特定于D的额外信息。

Here is the corrected code : 这是更正后的代码:

#include <string>
#include <vector>
#include <memory>

class A
{
public:
    A() = default;
    virtual ~A() {};
};

class B : public virtual A
{
public:
    B() = default;
    virtual ~B() {};
};

class C : public virtual A
{
public:
    C() = default;
    virtual ~C() {};
};

class D : public B, public C
{
public:
    D() = default;
    virtual ~D() {};
};


int main()
{
    { // this does not crashe anymore
        std::vector<std::unique_ptr<C>> v;
        std::unique_ptr<D> s1(new D());
        v.push_back(std::move(s1));
        std::unique_ptr<C> s2(new C());
        v.push_back(std::move(s2));
    }

    { // this is fine because you slice D into C, still that fine ?
        std::vector<C> v;
        D s1;
        v.push_back(s1);
        C s2;
        v.push_back(s2);
    }

    return 0;
}

See also 也可以看看


Note 注意

As stated in the comments, if you mark A destructor's as virtual, every derived class will also have a virtual destructor. 如评论中所述,如果将析构函数标记为虚拟,则每个派生类也将具有虚拟析构函数。 Writing it everywhere can make it more explicit. 到处写它可以使它更明确。 It is a matter of style. 这是一种风格问题。

Your "this is fine" example does slicing, the vector only contains instances of C , that's why it 'works' but does not do what you expected. 你的“这很好”的例子是切片,向量只包含C实例,这就是为什么它“有效”但却没有达到预期的效果。 The solution is as dkg points out is to use virtual dtors. 解决方案就像dkg指出的那样是使用虚拟dtors。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM