shared_ptr<void>如何知道使用哪个析构函数?

36

我编写了以下代码,以查看当shared_ptr<Thing>的最后一个引用是shared_ptr<void>并且其自身被销毁时,它会表现出什么行为。

#include <iostream>
#include <string>
#include <memory>

using namespace std;

struct Thing{
    ~Thing(){
        cout<<"Destroyed\n";
    }
    int data;
};

int main(){
    {
        shared_ptr<void> voidPtr;
        {
            shared_ptr<Thing> thingPtr = make_shared<Thing>();
            voidPtr = thingPtr;
        }
        cout<<"thingPtr is dead\n";
    }
    cout<<"voidPtr is dead\n";
    return 0;
}

输出为:

thingPtr is dead
Destroyed
voidPtr is dead

它表现出我喜欢的方式,但完全出乎意料,我想了解这里发生了什么。最初的共享指针不再存在,最终只是一个shared_ptr<void>。因此,我认为这个共享指针应该像持有void*一样,并且对于Thing::~Thing()一无所知,但它却调用了它。这是故意设计的吗?空指针共享指针是如何实现这一点的?


当复制时,我可以想象shared_ptr的原始删除器被保留。 - πάντα ῥεῖ
@πάνταῥεῖ 显然,删除器永远不会存储在任何共享指针实例中(无论是std::shared_ptr还是任何具有共享功能的“拥有”智能指针);它是动态分配的。 - curiousguy
2个回答

34
由共享指针共同拥有的共享状态还包含一个删除器,即函数对象,该对象在托管对象生命周期结束时被提供以释放它。我们甚至可以使用适当的构造函数指定自己的删除器。删除器存储方式及其经历的任何类型抹除都是实现细节。但可以说,共享状态包含一个函数,知道如何精确释放所拥有的资源。
现在,当我们使用make_shared<Thing>()创建具体类型的对象并未提供删除器时,共享状态设置为持有某些默认删除器,可释放Thing。实现可以仅从模板参数生成一个删除器。由于它作为共享状态的一部分存储,因此不依赖于可能共享状态所有权的任何shared_pointer<T>类型的T。它将始终知道如何释放Thing
因此,即使我们将voidPtr设置为仅剩的指针,删除器仍保持不变,并且仍然知道如何释放Thing。当voidPtr超出作用域时,它就会这样做。

2
shared_ptr 只知道如何处理具有已知接口的管理对象。该管理对象提供两个引用计数(弱引用用于自身,强引用用于被管理的对象),同时包含删除器(除非已知类型,否则无法访问)和要删除的指针(私有)。 shared_ptr 指向的类型和对象与其使用的管理对象是完全独立的问题,但出于健全性考虑,它不应该具有更长的生命周期。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接