9

I currently had a problem with storing a SDL_Window pointer as a std::unique_ptr.
What I tried was:

std::unique_ptr<SDL_Window> window_;

The solution:

std::unique_ptr<SDL_Window, void(*)(SDL_Window*)> window_;

The first attempt kept throwing errors in the memory header, saying SDL_Window is an incomplete type. Well I know that SDL_Window is a struct and can't be instanciated with

SDL_Window* window_ = new SDL_Window();

therefore the instanciation is done with SDL_CreateWindow(params).

Questions are:

  1. Why can't I call the default constructor (or any other) for SDL_Window?

  2. Why does the unique_ptr needs a deleter in this case, but not here:

    renderSystem_ = std::unique_ptr<Renderer::RenderSystem>(new Renderer::RenderSystem());
    

    RenderSystem being a class with just a default constructor, destructor.
    Is it because the unique_ptr can access the destructor, which acts as the deleter and doesn't need to come as a template argument?

genpfault
  • 51,148
  • 11
  • 85
  • 139
EmeraldOverflow
  • 122
  • 1
  • 9
  • 1
    There's a reason for this. When you create a pointer to SDL_Window, it should be a nullptr. Why? Because you'll most likely be calling SDL_CreateWindow which allocates memory for you. – Poriferous Apr 03 '15 at 01:16
  • So basically it is not allowed to allocate memory yourself because SDL_CreateWindow knows better? How exactly can this be achieved (f.e. in my own class)? I've read about the delete operator, but I don't think deleting a default constructor would make much sense – EmeraldOverflow Apr 03 '15 at 01:23
  • 4
    Bear in mind that SDL is written in C and unfortunately C++ users like us simply have to adapt to how SDL does it. You don't call delete window_ for example, you call SDL_DestroyWindow(window_) which deallocates memory. Anything non-SDL can use unique_ptrs and new and delete just as normal, but because SDL being written in C doesn't have unique_ptr nor new and delete, it doesn't recognise the syntax you're using. Even if you were able to call new SDL_Window it still wouldn't make sense since that allocated memory would become overridden by what's returned by SDL_CreateWIndow(). – Poriferous Apr 03 '15 at 01:31

2 Answers2

9

The SDL_Window type is, just like the compiler says, incomplete.

The SDL library is using a common pattern in C language: pointers to incomplete type.

At the point you create the unique pointer, the SDL_Window type looks to the compiler like this:

struct SDL_Window;

That's one way you can create an incomplete type.

The compiler doesn't know anything except that SDL_Window is a type, and not a global variable or a function. This also means it cannot assume what size it has, it cannot assume that it has any constructors or a destructor.

As for the unique pointer to the SDL_Window, another way is to use this:

struct SDLWindowDestroyer
{
    void operator()(SDL_Window* w) const
    {
        SDL_DestroyWindow(w);
    }
};

std::unique_ptr<SDL_Window, SDLWindowDestroyer> window_;

Now you don't need to provide a function in a constructor to the window_

milleniumbug
  • 15,379
  • 3
  • 47
  • 71
5

I find this cleaner:

    auto window = std::unique_ptr<SDL_Window, std::function<void(SDL_Window *)>>(
            SDL_CreateWindow("Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, kWindowWidth, kWindowHeight, 0),
            SDL_DestroyWindow
    );
Siamaster
  • 941
  • 12
  • 19