Reputation: 836
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.
Upvotes: 8
Views: 6237
Reputation: 13423
I would go with decltype
:
std::unique_ptr<SDL_Surface, decltype(&FreeSurface)> uptr_1(
CreateSurface(),
FreeSurface
);
Upvotes: 2
Reputation: 36792
Is uptr_1 correctly declared and initialized to nullptr
Yes, a default constructed unique_ptr
will refer to null.
if so, how can I assign the pointer and the deleter function?
You should be constructing the unique_ptr
with arguments
std::unique_ptr<SDL_Surface, std::function< void (SDL_Surface *) > > uptr_1{CreateSurface(), FreeSurface};
Alternatively, after the default construction you could use move assignment with a temporary
uptr_1 = std::unique_ptr<SDL_Surface, std::function< void (SDL_Surface *) > >{CreateSurface(), FreeSurface};
As you've suggested yourself, a type alias can help
using SDL_Uptr = std::unique_ptr<SDL_Surface, std::function< void (SDL_Surface *)>>;
SDL_Uptr uptr_1;
uptr_1 = SDL_Uptr{CreateSurface(), FreeSurface};
An intermediate function could help simplify this if it becomes repetitive (which it probably will if you make a lot of them).
std::unique_ptr<SDL_Surface, void (*)(SDL_Surface *)>
make_sdl_ptr() {
return std::unique_ptr<SDL_Surface, void (*)(SDL_Surface *)>{CreateSurface(), FreeSurface};
}
You could then call this with auto uptr = make_sdl_ptr();
Angew's answer with a DefaultConstructible deleter calling your function is also a really nice solution.
Upvotes: 1
Reputation: 171117
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());
Upvotes: 11