多重继承和unique_ptr销毁
Multiple inheritance and unique_ptr destruction
我有一个经典的(可能有问题的)多重继承菱形方案。
- B继承A
- C继承A
- D继承C和B
我想要一个可以包含C
或D
的std::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
的指针删除类D
,则将调用~C()
析构函数,并且将错过清理的重要部分。
还要注意,在您的第二部分(不使用unique_ptr
),您做了一些对象切片。这意味着您正在将类型为D
的s1
的副本创建为类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;
}
参见
- 何时使用虚析构函数?
- 什么是对象切片?
注意
如注释中所述,如果将析构函数标记为虚函数,则每个派生类也将具有虚析构函数。把它写在任何地方都可以使它更明确。这是一个风格问题。
你的"这很好"的例子做切片,向量只包含C
的实例,这就是为什么它"工作",但不做你所期望的。正如dkg指出的那样,解决方案是使用虚拟医生。
相关文章:
- std::threads可以从Windows DLL中的全局变量创建/销毁吗?
- 派生类销毁的最佳实践是什么
- CLANG 编译器 说:变量"PTR"可能未初始化
- 当一个新对象被分配到它的地址时,对象是否必须被销毁
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 将 ptr 传递给 ptr 到 A 作为参数传递给 A 的函数是不好的做法吗?
- WinAPI 在单击第一个对话框上的按钮控件并销毁第一个对话框后创建第二个对话框
- 如何在调用析构函数时优雅地停止/销毁带有阻塞调用C++线程?
- C++:在被本地字符串捕获后释放或销毁 malloc'd char *?
- 如何在不销毁对象的情况下返回对象列表
- C++:处理线程本地对象销毁
- 为共享 ptr 向量实现复制 c'tor?
- 将通用对象传递给 Rust 并在使用后传递回 C++ 进行销毁
- 字符和整数中 **(ptr+1) 的值差异
- C++对象的创建和销毁
- C++:在不中断共享的情况下通过引用传递共享 PTR?
- 如何将派生类从基 ptr 分配给 nlohmann::json
- c++ 何时/为什么由值构造/销毁捕获变量
- 引用 std::shared:ptr 以避免引用计数
- 在C++中,对象什么时候真正被销毁?delete(ptr)做什么