15

For the new operator, we have the std::nothrow version:

std::unique_ptr<T> p = new(std::nothrow) T();

Do we have something like this for the std::make_shared or std::make_unique?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
jack sparow
  • 339
  • 3
  • 9

1 Answers1

12

No, we don't. Looking through the cppreference pages for make_unique and make_shared, we see that every version uses the default new overload.

It is not difficult to implement one, though, something like this:

template <class T, class... Args>
std::unique_ptr<T> make_unique_nothrow(Args&&... args)
    noexcept(noexcept(T(std::forward<Args>(args)...)))
{
    return std::unique_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
}

template <class T, class... Args>
std::shared_ptr<T> make_shared_nothrow(Args&&... args)
    noexcept(noexcept(T(std::forward<Args>(args)...)))
{
    return std::shared_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
}

(Note that this version of make_shared_nothrow does not avoid double allocation as make_shared does.) C++20 added many new overloads for make_unique, but they can be implemented in a similar way. Also, per comment,

Don't forget to check the pointer before using it, when using this version. — Superlokkus Jul 18 '19 at 10:46

L. F.
  • 19,445
  • 8
  • 48
  • 82
  • 4
    Don't forget to check the pointer before using it, when using this version. – Superlokkus Jul 18 '19 at 10:46
  • 2
    "*we see that every version uses the default new overload.*" `allocate_shared` uses the provided allocator, not `new`. Also, if a user wants to use `nothrow` `new`, that probably means they don't want to turn on exception handling period. – Nicol Bolas Jul 19 '19 at 04:00
  • @NicolBolas I absolutely can't imagine how `allocate_shared` got in there ... Thank you! – L. F. Jul 19 '19 at 04:01
  • @NicolBolas As for exception handling, I wanted to keep consistent with the expression `new (nothrow) T(args...)`. So I propagate the exceptions thrown by the constructor. – L. F. Jul 19 '19 at 04:03
  • 1
    @L.F.: My point is that `new(std::nothrow)` will work in an exception-less build environment, reporting failure to allocate memory with `nullptr`. your suggestion will not, because the system trying to throw `std::bad_alloc` will *fail*, because exception handling is turned off. – Nicol Bolas Jul 19 '19 at 04:04
  • @NicolBolas You are right. I have reverted my edit. Can you think of a way to efficiently implement `make_shared_nothrow` to avoid double allocation? – L. F. Jul 19 '19 at 04:14
  • 1
    @L.F.: Not really. There is no provision in the allocator model for failure to allocate to be signaled by returning null, so `allocate_shared` isn't available. – Nicol Bolas Jul 19 '19 at 13:25