Gogogo
Gogogo

Reputation: 257

Smart pointer(unique_ptr) custom deleter error C2027 & C2338

I try to use smart pointers with SDL2 and I need a custom deleter. I use this code and get errors C2027 (using the undefined type SDL_Texture) & C2338 (can't delete an incomplete type)

ftexture = std::make_unique<SDL_Texture>(TTF_RenderText_Solid(font, fontData.c_str(), fontColor),
        [=](SDL_Texture* texture) {SDL_DestroyTexture(texture); });

This variable in my class looks like this:

std::unique_ptr <SDL_Texture> ftexture = nullptr;

Upvotes: 0

Views: 411

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 597186

First, TTF_RenderText_Solid() returns an SDL_Surface*, not an SDL_Texture*. SDL_Surface does not derive from SDL_Texture.

Second, you can't specify a custom deleter with std::make_unique(). The 1st template argument is used as the T type of the resulting std::unique_ptr, and the remaining template arguments are used for the input parameters, which are all passed to T's constructor. In your example, T is SDL_Texture, and there is no constructor of SDL_Texture that takes an SDL_Surface* and a lambda as input.

To use a custom deleter, you need to specify the deleter's type as a template argument of std::unique_ptr, which std::make_unique() does not allow you to do, so you have to use std::unique_ptr directly.

The deleter should be a separate type rather than a lambda:

struct SDL_Surface_Deleter
{
    void operator()(SDL_Surface* surface) {
        SDL_FreeSurface(surface);
    } 
};

using SDL_Surface_ptr = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>;
SDL_Surface_ptr fsurface;

...

fsurface = SDL_Surface_ptr(
    TTF_RenderText_Solid(font, fontData.c_str(), fontColor)
);

But if you really want to use a lambda, you can do this instead:

using SDL_Surface_Deleter = void (*)(SDL_Surface*);
using SDL_Surface_ptr = std::unique_ptr<SDL_Surface, SDL_Surface_Deleter>;
SDL_Surface_ptr fsurface;

...

fsurface = SDL_Surface_ptr(
    TTF_RenderText_Solid(font, fontData.c_str(), fontColor),
    [](SDL_Surface* surface) { SDL_FreeSurface(surface); }
);

Or, you can just use SDL_FreeSurface() directly as the actual deleter:

using SDL_Surface_ptr = std::unique_ptr<SDL_Surface, decltype(&SDL_FreeSurface)>;
SDL_Surface_ptr fsurface;

...

fsurface = SDL_Surface_ptr(
    TTF_RenderText_Solid(font, fontData.c_str(), fontColor),
    &SDL_FreeSurface
);

Upvotes: 4

Related Questions