5

I'm finally getting to move my codebase to C++11, which results in mostly shorter and better code.

I find however that when I call functions with a new pointer, it's quite a bit longer than before:

void addCallback(Callback*);  // Takes ownership of callback.
// ...
addCallback(new Callback);    // Clear.

becomes

void addCallback(std::unique_ptr<Callback>);  // No comment needed now!
// ...
addCallback(std::move(std::unique_ptr<Callback>(new Callback)));  // bleh.

The proposed make_unique() template function would only somewhat improve this.

After a little experimentation, I just wrote a helper template function for this:

template <typename T>
auto move_ptr(T *t) -> decltype(std::move(std::unique_ptr<T>(t))) {
  return std::move(std::unique_ptr<T>(t));
}
// ..
addCallback(move_ptr(new Callback));  // Not bad!

and it seems to work fine - but surely I'm reinventing the wheel? (And if I'm not - are there any traps or possible errors with my move_ptr or whatever I end up calling it?)

Tom Swirly
  • 2,740
  • 1
  • 28
  • 44
  • in general instead of using "move" it should be "rvalue". because,from what I understand, std::move doesn't move anything, it just converts to a rvalue. so maybe call it rvalue_ptr , instead of move_ptr. .02 – jaybny Jun 03 '14 at 18:04

1 Answers1

16

You mean, you want to write something simpler than this line?

addCallback(std::move(std::unique_ptr<Callback>(new Callback)));  // bleh.

Well, the std::move() is superfluous as you can bind temporaries to rvalue references directly:

addCallback(std::unique_ptr<Callback>(new Callback));

Sadly, there is no std::make_unique() but a make_unique() is easy enough to write:

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

... which yields

addCallback(make_unique<Callback>());
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • 5
    ...and you might want to remove the `T* ptr` argument from your `make_unique` ;) – Daniel Frey Sep 08 '13 at 20:46
  • Marked as correct! Thanks (can't believe I didn't catch the redundant std::move). The one downside - I don't believe this will work in Visual Studio because of the variadic templates which [aren't yet implemented in VS](http://msdn.microsoft.com/en-us/library/vstudio/hh567368.aspx) - am I right? (I work on cross-platform applications...) – Tom Swirly Sep 08 '13 at 21:02
  • 1
    @Tom: [Just overload it for some arguments.](http://stackoverflow.com/a/12548031/500104) – Xeo Sep 08 '13 at 21:03
  • 9
    @TomSwirly: To motivate the usage of `make_unique` (even if writing it sucks =]), I'll note that using `make_unique` goes beyond simply being clearer, but it's also safer. Consider: `foo(std::unique_ptr(new T), std::unique_ptr(new T));` The compiler is allowed to evaluate the two new-expressions before constructing any `std::unique_ptr`'s. This means if the second `new T` throws, the first will actually be leaked, even if you hoped the smart pointer would work! `make_unique` ensures this creation is seen as atomic with respect to exceptions: `foo(make_unique(), make_unique())`. – GManNickG Sep 08 '13 at 21:35
  • Too late :-D I'm already using make_unique with that link pointed to by Xeo above so you're preaching to the choir. I replaced some huge number of raw pointer returns with unique_ptrs with only one or two errors. Even with clang, there were some new obscure-seeming C++ errors, but, well, I'm used to those by now. :-D – Tom Swirly Sep 09 '13 at 21:47