所以,我知道不将多态类析构函数设为虚会导致未定义的行为,正确的解决方法是将它们设为虚。话虽如此,为什么shared_ptr在析构时会“保存”你呢?(我在RHEL 8上使用gcc/g++)
class Base
{
public:
~Base()
{
std::cout << "Base dtor" << std::endl;
}
};
class Derrived : public Base
{
public:
~Derrived()
{
std::cout << "Derrived dtor" << std::endl;
}
};
int main()
{
// Derrived dtor NOT called! (I understand why!)
{
std::unique_ptr<Base> b = std::make_unique<Derrived>();
}
// Derrived and Base dtor called! WHY???
{
std::shared_ptr<Base> b = std::make_shared<Derrived>();
}
}
字符串
我正在处理一个代码库,shared_ptr隐藏了内存泄漏,当我为对象创建一个unique_ptr时,它就坏了。花了一分钟才找到原因。这是一个简单的修复,但我可以看到这隐藏了大量的内存泄漏。
现在我只是好奇为什么它是不同的?shared_ptr以某种方式跟踪对象的动态类型?
我尝试将shared_ptr更改为unique_ptr,预期会有相同的行为,但得到的是不同的行为。
1条答案
按热度按时间kmpatx3s1#
来自cppreference。
对于唯一指针(_P):
如果T是某个基类B的派生类,则
std::unique_ptr<T>
可以隐式转换为std::unique_ptr<B>
。结果std::unique_ptr<B>
的默认删除器将对B使用delete运算符,导致未定义的行为,除非B的析构函数是虚拟的。注意,std::shared_ptr的行为不同:std::shared_ptr将对类型T使用delete运算符,即使B的析构函数不是虚拟的,所拥有的对象也将被正确删除。对于shared_ptr,当从另一个shared_ptr构造shared_ptr时(情况8、9、10):
别名构造函数:构造一个shared_ptr,它与r的初始值共享所有权信息,但保存一个不相关的非托管指针ptr。如果这个shared_ptr是组中最后一个超出作用域的指针,它将为最初由r管理的对象调用存储的删除器
unique_ptr被设计为尽可能高效。
shared_ptr可以(很明显)共享对象,因此您可能希望在该对象上使用不同的指针类型,然后需要跟踪原始的删除器。相反,如果在对象的一个或另一个shared_ptr上使用删除器时,删除器的行为会有所不同,您会感到非常惊讶。