1

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.

Zeor137
  • 165
  • 1
  • 2
  • 11
  • Is the short version here, "How do I attach a pointer requiring a custom de-allocation function to be lifetime-maintained by a `std::shared_ptr` ? " – WhozCraig Nov 22 '20 at 02:29
  • @WhozCraig Yep, that's it – Zeor137 Nov 22 '20 at 02:48
  • @Sprite What I meant there was for a object from a class. Like Vector.push_back(obj); Here if the vector resizes it changes place copying everything to it's new addresses and calling the destructor for this object. I am not sure if this was clear. I will edit the question with some code. – Zeor137 Nov 22 '20 at 02:52
  • @Zeor137 I just misunderstood your question, sorry I deleted it before you explained. – Sprite Nov 22 '20 at 02:56
  • You can use [allocate_shared](https://en.cppreference.com/w/cpp/memory/shared_ptr/allocate_shared) to create shared_ptr. This mathod takes an [Allocator](https://en.cppreference.com/w/cpp/named_req/Allocator). In your Allocator implimentation you can use `get_picture` and `picture_close` for creation and destruction. – Ashutosh Raghuwanshi Nov 22 '20 at 03:10

1 Answers1

1

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.

WhozCraig
  • 65,258
  • 11
  • 75
  • 141