重置 std::shared_ptr 会导致重置其删除器吗?

Does resetting std::shared_ptr lead to resetting its deleter?

也许我误解了c++中智能指针的某些方面,但是执行这段代码后:

class cls
{
public:
    class deleter
    {
    public:
        const cls& obj;
        deleter(const cls& c) : obj(c) {}
        void operator()(int* num)
        {
            std::cout << "deleter was called" << std::endl;
            if (num)
            {
                std::cout << "num in deleter: " << *num << std::endl;
                if (*num == *obj.int_ptr)
                {
                    std::cout << "equal " << *num << " = " << *obj.int_ptr << std::endl;
                    delete num;
                }
                else
                    std::cout << "not equal" << std::endl;
            }
        }
    };

std::shared_ptr<int> int_ptr;
cls() : int_ptr(nullptr,deleter(*this)) {}
};

int main()
{
    cls obj;
    obj.int_ptr.reset(new int{15});
    return 0;   
}

输出:

deleter was called

0

我注意到 shared_ptr 中的 reset() 删除了在其构造函数中传递给它的自定义删除器。相反 unique_ptr 没有表现出这种行为,这对我来说很奇怪。

那么这是怎么回事?

删除器在 std::shared_ptr 中的存储方式与在 std::unique_ptr 中的存储方式不同。 std::unique_ptr 使用空基优化 (EBO) 来存储删除器,这意味着 std::unique_ptr 继承了删除器。 std::shared_ptr 不会这样做,这就是为什么两者之间的删除器 API 不同的原因。

std::shared_ptr 将删除器存储在控制块中。因此,您可以切换删除器并始终将 std::shared_ptr 与多种删除器一起使用,同时与指向相同数据的 std::shared_ptr 的所有其他实例共享它。

std::unique_ptr 不需要任何类型的东西,必要时将删除器存储在它的实例中。您还必须将 deleter 的用法指定为模板参数之一。

基本上,在 std::shared_ptr 中,删除器是数据的一部分,在 std::unique_ptr 中,删除器是 class.

的一部分

当我们给nullptr赋值或者在std::shared_ptr上调用reset时,会在清理内存后清除指针和getdeleter。 unique_ptr 的处理方式不同。

下面是库中的函数,它减少 shared_ptr 的计数,如果 reference_count 为零,则继续销毁:

void _Decref() noexcept { // decrement use count
    if (_MT_DECR(_Uses) == 0) {
        _Destroy();
        _Decwref();
    }
}

因此,一旦您重置并且引用 _count 为零,那么 shared_ptr 自定义删除器将因重置而被删除。