c++ 为什么shared_ptr和unique_ptr在dtors不是virtual时有不同的行为?

6ie5vjzr  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(80)

所以,我知道不将多态类析构函数设为虚会导致未定义的行为,正确的解决方法是将它们设为虚。话虽如此,为什么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,预期会有相同的行为,但得到的是不同的行为。

kmpatx3s

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管理的对象调用存储的删除器

  • 现在我很好奇为什么会有不同?shared_ptr是否以某种方式跟踪对象的动态类型?*

unique_ptr被设计为尽可能高效。
shared_ptr可以(很明显)共享对象,因此您可能希望在该对象上使用不同的指针类型,然后需要跟踪原始的删除器。相反,如果在对象的一个或另一个shared_ptr上使用删除器时,删除器的行为会有所不同,您会感到非常惊讶。

相关问题