我有经典(可能有问题的)多重继承钻石计划。
我想要一个可以包含std::vector
或C
的{{1}}
对象,所以我把它作为D
std::vector<C>
的爸爸和它
工作正常。
但是当我使用:D
时,我会在矢量被破坏时出现分段错误。
std::vector<std::unique_ptr<C>>
为什么会有区别?对我来说,即使是第一次实施也存在问题。
代码
** glibc detected *** ./a.out: free(): invalid pointer: 0x0000000009948018***
答案 0 :(得分:14)
您应该将析构函数声明为虚拟。否则,如果使用指向D
的指针删除了您的类C
,则将调用~C()
析构函数,并且将丢失清理的基本部分。
另请注意,在第二部分(不使用unique_ptr
)中,您可以进行一些对象切片。这意味着您要将s1
类型D
的副本创建到类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;
}
如评论中所述,如果将析构函数标记为虚拟,则每个派生类也将具有虚拟析构函数。 到处写它可以使它更明确。这是一种风格问题。
答案 1 :(得分:5)
你的&#34;这很好&#34;示例进行切片,向量仅包含{{1}}的实例,这就是为什么它的工作原理&#39;但没有达到你的预期。解决方案就像dkg指出的那样是使用虚拟dtors。