Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why std::make_unique instead of std::unique_ptr::make?

Tags:

Why did C++ adopt free functions for:

std::make_unique(...); std::make_shared(...); 

instead of using static member functions:

std::unique_ptr::make(...); // static std::shared_ptr::make(...); // static 

?

like image 364
vladon Avatar asked Mar 21 '17 09:03

vladon


People also ask

Why should I use Make_unique?

Using the 'make_unique' function to create the pointer helps solve this problem by guaranteeing the freeing of memory if an exception occurs. The C++17 standard, while still not specifying the exact evaluation order for arguments, provides additional guarantees.

What is std :: unique_ptr?

std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope. The object is disposed of, using the associated deleter when either of the following happens: the managing unique_ptr object is destroyed.

Does Make_unique throw?

A little late, but make_unique can itself throw according to cppreference: make_unique "may throw std::bad_alloc or any exception thrown by the constructor of T. If an exception is thrown, this function has no effect." So how is that exception safe?

Does Make_unique initialize memory?

Yes, all the elements will be value initialized by std::make_unique.


1 Answers

TL;DR: Static member functions always have access to private data but free functions only have access to private data when explicitly marked as friend. The choice to implement these functions as free functions (with a small number being implemented as friend functions) isn't a random historical artifact, but is a deliberate decision to improve encapsulation while having a consistent naming scheme for all of the std::make_x functions.


There are many standard factory functions in C++:

std::make_pair std::make_tuple std::make_unique std::make_shared //efficiency std::make_exception_ptr //efficiency std::make_move_iterator std::make_reverse_iterator std::make_error_code std::make_error_condition //And several more are proposed for C++17 

For all of the above, the make_x function can be implemented correctly using only the public interface of x. In the case of make_shared and make_exception_ptr, the most efficient implementation would require access to the internal data of the std::shared_ptr or std::exception_ptr. All the others can be implemented using just the public interface with zero performance penalty.

Implementing these functions as non-friend free-functions reduces the amount of code that has access to the private internals of the object (a desirable property, since when less code has access to private data, there are fewer places that have to be audited for operations that violate the invariants of the object, and fewer places that potentially need to be changed if the internals of the object change).

If make_shared were the only similar factory function, it might make sense for it to be a member function, but since the majority of such functions are not required to be friend functions to operate efficiently, make_shared is also implemented as a free-function, for the sake of consistency.

This is the correct design, as if static member make functions were consistently used, then in every case apart from make_shared and make_exception_ptr, the member function would unavoidably have excessive access to the private data of the x object. With the standardised design, the small number of make_x functions that need access to private data can be marked as friend, and the rest respect encapsulation correctly by default. If a non-member make_x were used in some cases and a static member make in others, the standard library would become inconsistent and more difficult to learn.

like image 153
Mankarse Avatar answered Nov 16 '22 08:11

Mankarse