Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this smart pointer wrapper for SDL types safe?

I thought about using something like the following so I don't have to remember to explicitly call destroyer functions at the end of methods:

#include <iostream>
#include <SDL2/SDL.h>
#include <memory>

int main()
{
    SDL_Init(SDL_INIT_VIDEO);

    std::unique_ptr<SDL_Window, decltype((SDL_DestroyWindow))>
        win { SDL_CreateWindow("asdf", 100, 100, 640, 480, SDL_WINDOW_SHOWN),
                  SDL_DestroyWindow };
    if (!win.get())
    {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateWindow Error: %s",
                SDL_GetError());
        return 1;
    }

    SDL_Quit();
}

I'm not sure if it's the best approach. I'm worried that this doesn't do what I want it to do even though it looks simple enough. Are there any subtle bugs to this approach?

like image 639
user6326610 Avatar asked Mar 12 '23 08:03

user6326610


2 Answers

Introduce a new scope and you should be OK:

int main()
{
  SDL_Init(SDL_INIT_VIDEO);

  {
    std::unique_ptr<SDL_Window, decltype((SDL_DestroyWindow))>
      win { SDL_CreateWindow("asdf", 100, 100, 640, 480, SDL_WINDOW_SHOWN),
        SDL_DestroyWindow };
    if (!win.get())
    {
      SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateWindow Error: %s",
          SDL_GetError());
      return 1;
    }
  } // win destroyed before SQL_Quit

  SDL_Quit();
}
like image 138
user6326732 Avatar answered Mar 19 '23 01:03

user6326732


Use RAII even more:

struct SDL_RAII
{
    SDL_RAII() { SDL_Init(SDL_INIT_VIDEO); }

    ~SDL_RAII() noexcept {
        try {
            SDL_Quit();
        } catch (...) {
            // Handle error
        }
    }

    SDL_RAII(const SDL_RAII&) = delete;
    SDL_RAII(SDL_RAII&&) = delete;
    SDL_RAII& operator=(const SDL_RAII&) = delete;
    SDL_RAII& operator=(SDL_RAII&&) = delete;
};

and be DRY by factorizing the deleter:

template <typename Object, void (*DeleterFun)(Object*)>
struct Deleter
{
    void operator() (Object* obj) const noexcept
    {
        try {
            DeleterFun(obj);
        } catch (...) {
            // Handle error
        }
    }
};

template <typename Object, void (*DeleterFun)(Object*)>
using UniquePtr = std::unique_ptr<Object, Deleter<Object, DeleterFun>>;

Then, some types for SDL:

using Unique_SDL_Window = UniquePtr<SDL_Window, SDL_DestroyWindow>;
using Unique_SDL_Surface = UniquePtr<SDL_Surface, SDL_FreeSurface>;
// ...

And finally:

int main()
{
    SDL_RAII SDL_raii;

    Unique_SDL_Window win{ SDL_CreateWindow("asdf", 100, 100, 640, 480, SDL_WINDOW_SHOWN)};

    if (!win.get())
    {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "SDL_CreateWindow Error: %s",
                     SDL_GetError());
        return 1;
    }
    return 0;
}
like image 45
Jarod42 Avatar answered Mar 19 '23 00:03

Jarod42