top | item 7610898

(no title)

michaelrmmiller | 12 years ago

The other downside to their approach is that you have to pass the function into the constructor every time you construct an object.

A similar alternative would be to template the deleter on the type of the function and then a specific function. This way you can wrap functions with non-void return values. Something like:

  template<typename FuncType, FuncType& F> struct deleter { ... };
  using unique_cptr = std::unique_ptr<void, deleter<decltype(free), free>>;
The other cool thing I learned recently is you can actually use the custom deleter to override the wrapped type by typedef'ing pointer in your deleter class. You can use this to wrap C-style file descriptors in a unique_ptr.

discuss

order

humanrebar|12 years ago

> The other downside to their approach is that you have to pass the function into the constructor every time you construct an object.

That's why the suggest a make_window function at the bottom of the post. The end-user just calls:

    auto window = sdl2::make_window("Title", /* window sizes and stuff */);
The optimizer should inline all the extra wrappers away, so there's no overhead for doing as the article suggests.

michaelrmmiller|12 years ago

True but that means you need a wrapper function for each type you want to create or you need to use the more general function, defeating the purpose.

It also obscures the type of the object. That can be okay if it's only used as a temporary local, but problematic if you ever need to store it as a member or return it from another function. The type signature is verbose and not very descriptive, either. Compare that to:

  namespace sdl2 {
    using window = std::unique_ptr<SDL_Window, deleter<decltype(SDL_DestroyWindow), SDL_DestroyWindow>>;
  }
  ...
  sdl2::window window{SDL_CreateWindow(...)};
If you wanted to do something like what they have, I would create a variant on C++14's std::make_unique. That could look like:

  template<typename T> struct deleter_traits;

  template<> struct deleter_traits<SDL_Window>
  {
    using custom_deleter = deleter<decltype(SDL_DestroyWindow), SDL_DestroyWindow>;
  }

  template<typename T, typename... Args> create_unique(Args&&... args)
  {
    return std::unique_ptr<T, typename deleter_traits<T>::custom_deleter>{new T(std::forward(args))};
  }

  sdl2::window window = create_unique<SDL_Window>(...);
That looks a lot cleaner to me, at least. And instead of having to write a new function for each type, you just add a new deleter_traits specialization.

(I haven't actually compiled any of this so it's probably riddled with syntax errors... hopefully the point still comes across!)