Zeor137
Zeor137

Reputation: 195

How to create a custom shared_ptr?

Say I have a library SXY which gives me a picture from a file:

Picture * pic;

pic=get_picture("directory/file")

And I share it over multiple functions. But I want to call picture_close(pic) to dellocate it only when I am done and all these functions went out of a scope. shared_ptr already does that but if I do:

shared_ptr<Picture> pic=get_picture("file")

It won't won't compile first because the function get_picture returns a pointer to a Picture and not a shared_ptr and when it goes out of scope it won't call picture_close(pic) which is the proper way to deallocate it. Is there by any chance a custom form of a shared pointer that calls a sort of destructor only when all references to this picture went out of scope?

If I do a object and call the picture_close(pic) in the destructor of it's class it will call the destructor and deallocate the picture whenever the object is copied which is what I am having.

Upvotes: 1

Views: 891

Answers (1)

WhozCraig
WhozCraig

Reputation: 66194

I think you're asking how to provide custom-deleter capabilities to a std::shared_ptr, and then utilize that by attaching your pre-allocated point therein. The most common use of this would be some pre-existing handle-type APIs that require such workflows.

One way to do it is like the following code. I've provided mock versions of get_picture and picture_close, as well as a Picture class, but hopefully you get the idea.

#include <iostream>
#include <vector>
#include <memory>

struct Picture
{
    Picture() { std::cout << __PRETTY_FUNCTION__ << '\n'; }
    virtual ~Picture() { std::cout << __PRETTY_FUNCTION__ << '\n'; }
    
    void report() { std::cout << "report!\n"; }
};

Picture *get_picture()
{
    return new Picture();
}

void picture_close(Picture *p)
{
    std::cout << "deleting picture\n";
    delete p;
}

void foo(std::vector<std::shared_ptr<Picture>> pictures)
{
    for (auto& sp : pictures)
        sp->report();
}

int main()
{
    std::vector<std::shared_ptr<Picture>> pictures;
    for (int i=0; i<5; ++i)
        pictures.emplace_back(get_picture(), picture_close);
    foo(pictures);
}

Output

Picture::Picture()
Picture::Picture()
Picture::Picture()
Picture::Picture()
Picture::Picture()
report!
report!
report!
report!
report!
deleting picture
virtual Picture::~Picture()
deleting picture
virtual Picture::~Picture()
deleting picture
virtual Picture::~Picture()
deleting picture
virtual Picture::~Picture()
deleting picture
virtual Picture::~Picture()

You can find out more about the various mechanisms you can create and maintain shared pointers here. Bookmark that site, btw; it's a real asset in your war chest as you're exposed to more and more of the C++ standard library.

Upvotes: 1

Related Questions