多重继承和 unique_ptr 破坏

Multiple inheritance and unique_ptr destruction

我有经典的(可能有问题的)多重继承菱形方案。

我想要一个可以包含 CDstd::vector 对象,所以我将其设为 std::vector<C>,即 D 的父亲和它 工作正常。

BUT 当我使用:std::vector<std::unique_ptr<C>> 然后我在破坏向量时出现分段错误。

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

为什么会有差异?对我来说,即使是第一次实施也是有问题的。

代码

#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;
};

您应该将析构函数声明为虚拟的。否则,如果使用指向 C 的指针删除了 class D,那么将调用 ~C() 析构函数并且将错过清理的重要部分。

另请注意,在第二部分(不使用 unique_ptr)中,您进行了一些对象切片。这意味着您正在将类型 Ds1 的副本创建到 class C 的新对象中,因此您可能会丢失特定于 D 的额外信息.

这是更正后的代码:

#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;
}

另见


备注

如评论中所述,如果将析构函数标记为虚拟,则每个派生的 class 也将具有虚拟析构函数。 把它写在任何地方都可以使它更明确。这是风格问题。

您的 "this is fine" 示例进行切片,向量仅包含 C 的实例,这就是为什么它 'works' 但没有按照您的预期进行。正如 dkg 指出的那样,解决方案是使用虚拟 dtors。