Nikita128
Nikita128

Reputation: 462

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

maybe I misunderstood some aspects of smart pointers in c++, but after executing this code:

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;   
}

Output:

deleter was called

0

I noticed that reset() from shared_ptr removes custom deleter, that was passed to it in its constructor. On the contrary unique_ptr doesn't show such behavior, which seemed strange to me.

So what is going on here?

Upvotes: 1

Views: 905

Answers (3)

Build Succeeded
Build Succeeded

Reputation: 1150

When we assign the nullptr or call reset on std::shared_ptr, it will clear the pointer and getdeleter after cleaning memory. The way it is done for unique_ptr is different.

Below is the function from library which decrement the count of shared_ptr and if reference_count is zero then proceed with destruction:

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

So, once you reset and reference _count is zero then the shared_ptr the custom deleter will be removed due to reset.

Upvotes: 1

ALX23z
ALX23z

Reputation: 4703

std::shared_ptr stores the deleter inside the control block. So you can switch the deleter and use std::shared_ptr with large variety of deleters all the while sharing it with all other instances of the std::shared_ptr that point to the same data.

std::unique_ptr needs nothing of the sort and stores the deleter within its` instance when must. Also you have to specify usage of deleter as one of the template parameters.

Basically, in std::shared_ptr deleter is part of the data and in std::unique_ptr deleter is part of the class.

Upvotes: 3

Rian Quinn
Rian Quinn

Reputation: 1996

The deleter is stored differently in the std::shared_ptr than it is in the std::unique_ptr. The std::unique_ptr uses empty base optimizations (EBO) to store the deleter which means the std::unique_ptr inherits the deleter. The std::shared_ptr does not do this, which is the why the deleter APIs are different between the two.

Upvotes: 0

Related Questions