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

How does shared_ptr<void> know which destructor to use?

我写了下面的代码来查看当 shared_ptr<void> 最后一次引用 shared_ptr<Thing> 并且它自己被销毁时它会如何表现。

#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(),但它会调用它。这是设计使然,对吧? void 共享指针是如何做到这一点的?

共享指针共同拥有的共享状态还包含一个删除器,一个类似于对象的函数,在其生命周期结束时将其提供给托管对象以释放它。我们甚至可以使用 appropriate constructor 指定我们自己的删除器。删除器是如何存储的,以及它所经历的任何类型擦除都是一个实现细节。但足以说明共享状态包含一个函数,该函数确切地知道如何释放所拥有的资源。

现在,当我们使用 make_shared<Thing>() 创建一个具体类型的对象并且不提供删除器时,共享状态将设置为保存一些可以释放 Thing 的默认删除器。该实现可以单独从模板参数生成一个。由于它作为共享状态的一部分存储,因此它不依赖于可能共享状态所有权的任何 shared_pointer<T> 的类型 T。它总是知道如何释放 Thing.

所以即使我们让 voidPtr 成为唯一剩余的指针,删除器仍然保持不变,并且仍然知道如何释放 Thing。当 voidPtr 超出范围时它会做什么。

shared_ptr 只知道如何处理具有已知接口的管理对象。该管理对象提供两个引用计数(自身弱,被管理对象强),以及包含删除器(除了调用它之外的访问仅在类型已知时提供)和要删除的指针(私有) .

shared_ptr 指向的类型和对象与它使用的管理对象完全不同,尽管出于理智考虑,它不应该存在更长时间。