简体   繁体   English

为什么std :: make_unique而不是std :: unique_ptr :: make?

[英]Why std::make_unique instead of std::unique_ptr::make?

Why did C++ adopt free functions for: 为什么C ++采用免费函数:

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

instead of using static member functions: 而不是使用静态成员函数:

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

?

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 . TL; DR:静态成员函数始终可以访问私有数据,但是当明确标记为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. 将这些函数实现为自由函数(少数被实现为友元函数)的选择不是随机的历史工件,而是为所有std::make_x提供一致命名方案的改进封装的有意决定。职能。


There are many standard factory functions in C++: 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 . 对于上述所有内容,只使用x的公共接口就可以正确实现make_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 . 对于make_sharedmake_exception_ptr ,最有效的实现需要访问std::shared_ptrstd::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. 如果make_shared是唯一类似的工厂函数,那么它成为一个成员函数可能是有意义的,但由于大多数此类函数不需要friend函数来有效运行,因此make_shared也实现为自由函数,为了一致性。

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. 这是正确的设计,就好像静态成员make函数一直被使用,然后在除了make_sharedmake_exception_ptr之外的每种情况下,成员函数都不可避免地会过度访问x对象的私有数据。 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. 使用标准化设计,需要访问私有数据的少量make_x函数可以标记为friend ,其余部分默认正确封装。 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. 如果非成员make_x在某些情况下使用和静态成员make别人,标准库将变得不一致,比较难学。

Consistency . 一致性

I don't think that there is any compelling reason to have the ::make syntax instead of the current one. 我不认为有任何令人信服的理由使用::make语法而不是当前语法。 I assume that make_unique and make_shared were preferred to a static ::make function to stay consistent with the existing std::make_pair and std::make_heap functions, that existed pre-C++11. 我假设make_uniquemake_shared比static ::make函数更喜欢与现有的std::make_pairstd::make_heap函数保持一致,这些函数存在于C ++之前的11版本中。


Note that std::make_pair has a big advantage: it automatically deduces the types of the resultant pair from the function call: 请注意, std::make_pair有一个很大的优势:它会自动从函数调用中推导出结果对的类型:

auto p0 = std::make_pair(1, 1.f); // pair<int, float>

If we had std::pair::make , then we would have to write: 如果我们有std::pair::make ,那么我们必须写:

auto p1 = std::pair<int, float>::make(1, 1.f);

which defeats the purpose of make_pair . 这违背了make_pair的目的。


  • I therefore assume that make_unique and make_shared were chosen because developers were already used to make_pair and similar functions. 因此我假设选择了make_uniquemake_shared ,因为开发人员已经习惯了make_pair和类似的函数。

  • make_pair was chosen instead of pair::make for the aforementioned benefits. 选择make_pair代替pair::make以获得上述好处。

There is not a concrete reason other than convention alone - a static-class function can do everything a global function can do (functionality wise). 除了约定之外没有具体的原因 - 静态类函数可以完成全局函数可以做的所有事情(功能明​​智)。
C++ prefers global functions (for utility functions) which contained inside a defined namespace. C ++更喜欢包含在已定义的命名空间内的全局函数(用于实用程序函数)。
Other programming languages (such as Java) prefer static public functions, as global functions are not supported. 其他编程语言(如Java)更喜欢静态公共函数,因为不支持全局函数。

this is not new to make_*** , other examples exists: 这不是新的make_*** ,其他例子存在:

std::this_thread::XXXX instead of std::thread::XXXX_current std::this_thread::XXXX而不是std::thread::XXXX_current
although it might had sense to put function which relates to the current thread of execution as static functions inside thread class, they are made global inside this_thread namespace. 虽然将与当前执行线程相关的函数作为静态函数放在thread类中可能有意义,但它们在this_thread命名空间内this_thread全局。

also, we could have something like std::container::sort which std::container is a helper class for containers, but we have std::sort instead. 另外,我们可以使用类似std::container::sort东西,其中std::containerstd::container的辅助类,但我们有std::sort

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么 C++ 需要 std::make_unique 而不是转发的 unique_ptr 构造函数? - Why does C++ need std::make_unique over forwarded unique_ptr constructor? std :: make_unique会发生什么 <T> ()分配给std :: unique_ptr <T> ? - What happens when std::make_unique<T>() assigns to std::unique_ptr<T>? std :: make_unique和std :: unique_ptr之间的区别与内部新 - Differences between std::make_unique and std::unique_ptr with new internally 我怎样才能转换std :: make_unique <derived> ()到std :: unique_ptr <base> - How can I convert std::make_unique<derived>() to std::unique_ptr<base> std::make_unique 和 std::unique_ptr 与 new 的区别 - Differences between std::make_unique and std::unique_ptr with new 带有前向声明的 std::make_unique 和 std::unique_ptr 之间的奇怪行为 - Strange behavior between `std::make_unique` and `std::unique_ptr` with forward declaration 将make_unique指定为std :: move()是否为空unique_ptr? - Does assigning make_unique require std::move() to an empty unique_ptr? 没有重载函数“ std :: make_unique”的实例与参数列表匹配,但可与unique_ptr构造函数一起使用 - no instance of overloaded function “std::make_unique” matches the argument list, but works with unique_ptr constructor unique_ptr,make_unique和多态 - unique_ptr, make_unique and polymorphism 为什么要使用make_unique调用初始化unique_ptr? - Why initialize unique_ptr with a make_unique call?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM