Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confused using unique_ptr and a custom deleter

I'm trying to use unique_ptr with a custom deleter for SDL_Surface type. This is only an example using int type, but I hope you get the idea.

#include <iostream>
#include <functional>
#include <memory>

typedef int SDL_Surface;


SDL_Surface * CreateSurface()
{
    SDL_Surface * p = new SDL_Surface;
    return p;
}

void FreeSurface(SDL_Surface *p)
{
    delete p;
}

int main() {
    std::unique_ptr<SDL_Surface, std::function< void (SDL_Surface *) > > uptr_1; 

    //how to assign a value to uptr_1 and the deleter? 

    return 0;
}

Is uptr_1 correctly declared and initialized to nullptr? If so, how can I assign the pointer and the deleter function?

And how can I encapsulate this: std::unique_ptr< SDL_Surface, std::function< void (SDL_Surface *) > > with the deleter to not always write that line on every SDL_Surface I want, another typedef?

I'm just starting to learn C++11 features and this is a hard one for me.

like image 791
FrameBuffer Avatar asked Feb 19 '15 14:02

FrameBuffer


People also ask

When should we use unique_ptr?

Use unique_ptr when you want to have single ownership(Exclusive) of the resource. Only one unique_ptr can point to one resource. Since there can be one unique_ptr for single resource its not possible to copy one unique_ptr to another. A shared_ptr is a container for raw pointers.

Does unique_ptr call Delete?

An explicit delete for a unique_ptr would be reset() . But do remember that unique_ptr are there so that you don't have to manage directly the memory they hold. That is, you should know that a unique_ptr will safely delete its underlying raw pointer once it goes out of scope.

What happens when unique_ptr goes out of scope?

std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope. The object is disposed of, using the associated deleter when either of the following happens: the managing unique_ptr object is destroyed.

What happens to unique_ptr after move?

"Moving" transfers ownership to a new unique_ptr and resets the old unique_ptr .


2 Answers

You can initialise the unique_ptr with a pointer and deleter, or use = normally if re-assigning later:

std::unique_ptr<SDL_Surface, std::function<void (SDL_Surface *)>> uptr_1(CreateSurface(), &FreeSurface);

uptr_1 = std::unique_ptr<SDL_Surface, std::function<void (SDL_Surface *)>>(CreateSurface(), &FreeSurface);

Refer to suitable docs for details.

To shorten the long type, you can indeed use a type alias (typedef or using):

typedef std::unique_ptr<SDL_Surface, void (*)(SDL_Surface*)> Surface_ptr;

//or

using Surface_ptr = std::unique_ptr<SDL_Surface, void (*)(SDL_Surface*)>;

Notice I've actually used void (*)(SDL_Surface*) for the deleter type. If you know you'll always pass an actual function (or stateless lambda) in, there's no reason to drag in std::function, which has some overhead due to type erasure.

Also, you can shorten it even further by creating a default-constructible functor for the deleter:

struct FreeSurface_Functor
{
  void operator() (SDL_Surface *s) const
  {
    FreeSurface(s);
  }
};

That way, you can make the type of your pointer std::unique_ptr<SDL_Surface, FreeSurface_Functor> (possibly aliased) and you don't have to provide the deleter; it will be default-constructed:

std::unique_ptr<SDL_Surface, FreeSurface_Functor> uptr_1(CreateSurface());
like image 159
Angew is no longer proud of SO Avatar answered Sep 28 '22 08:09

Angew is no longer proud of SO


I would go with decltype:

std::unique_ptr<SDL_Surface, decltype(&FreeSurface)> uptr_1(
          CreateSurface(),
          FreeSurface
);
like image 27
lvella Avatar answered Sep 28 '22 07:09

lvella