brevzin / cpp_proposals

My WG21 proposals
35 stars 22 forks source link

Add std::make_unique_nothrow and std::make_shared_nothrow functions #40

Closed klappdev closed 1 year ago

klappdev commented 1 year ago

Looking at cppreference, the implementations of the _std::makeunique() and _std::makeshared() functions use a simple call of the new operator. https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique https://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared

And the implementations of the three main compilers confirm this. https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/unique_ptr.h https://github.com/llvm/llvm-project/blob/main/libcxx/include/__memory/unique_ptr.h https://github.com/microsoft/STL/blob/main/stl/inc/memorу

Using _std::makeunique() and _std::makeshared() can result to a std::bad_alloc exception, being thrown if there is not enough memory in system. In an environment where exceptions are disabled, it must use the new operator with std::nothrow.

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

The _std::makeshared() and _std::makeunique() functions are more efficient and could prevent double allocations. It is proposed to add _std::make_uniquenothrow() and _std::make_sharednothrow() functions, which could be implemented as follow.

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)...));
}

The boost library already implements similar functions. https://www.boost.org/doc/libs/1_63_0/boost/move/make_unique.hpp