std::make_unique_for_overwrite() 相对于 std::make_unique() 做什么?

ein*_*ica 10 c++ smart-pointers c++20

似乎在 C++20 中,我们获得了一些额外的智能指针实用函数,包括:

template<class T> unique_ptr<T> make_unique_for_overwrite();
template<class T> unique_ptr<T> make_unique_for_overwrite(size_t n);
Run Code Online (Sandbox Code Playgroud)

std::make_sharedwith 一样std::shared_ptr。为什么不是现有的功能:

template<class T, class... Args> unique_ptr<T> make_unique(Args&&... args); // with empty Args
template<class T> unique_ptr<T> make_unique(size_t n);
Run Code Online (Sandbox Code Playgroud)

足够的?现有的不使用对象的默认构造函数吗?

注意:在这些函数的早​​期提案中,名称是make_unique_default_init().

ein*_*ica 10

这些新功能不同的:

  • 原始make_XYZ始终初始化指向的值(“显式初始化”,参见标准中的§ class.expl.init )。
  • make_XYZ_for_overwrite:执行指向值的“默认初始化”(参见 dcl.init,标准中的第 7 段);在典型的机器上,这意味着实际上没有对非类、非数组类型进行初始化。(是的,该术语有点令人困惑;请阅读链接中的段落。)

这是普通指针的一个特性,它在智能指针实用程序函数中不可用:使用常规指针,您可以在不实际初始化指向值的情况下进行分配:

new int
Run Code Online (Sandbox Code Playgroud)

对于唯一/共享指针,您只能通过包装现有指针来实现这一点,如下所示:

std::unique_ptr<int[]>(new int[n])
Run Code Online (Sandbox Code Playgroud)

现在我们有一个包装函数。

注意:请参阅相关的 ISO C++ WG21提案以及此 SO 答案

  • 我不知道你为什么不使用正确的术语来表达它的含义:( (3认同)

Bar*_*rry 9

allocate_shared, make_shared, 和make_unique都通过执行与 等效的操作来初始化底层对象new T(args...)。在零参数的情况下,这简化为new T()- 也就是说,它执行值初始化。许多情况下的值初始化(包括像int和这样的标量类型char、它们的数组和它们的聚合)执行零初始化- 也就是说,这是将一堆数据归零的实际工作。

也许您想要那个并且这对您的应用程序很重要,也许您不想要。从P1020R1,介绍了该功能最初被命名的文件make_unique_default_initmake_shared_default_init以及allocate_shared_default_init(这是从更名meow_default_initmeow_for_overwrite全国选票C ++ 20评论过程中):

内置类型的数组(例如unsigned char或 )double在分配后立即由用户整体初始化的情况并不少见。在这些情况下,由allocate_sharedmake_shared和执行的值初始化make_unique是多余的并且会损害性能,因此需要一种选择默认初始化的方法。

也就是说,如果您正在编写如下代码:

auto buffer = std::make_unique<char[]>(100);
read_data_into(buffer.get());
Run Code Online (Sandbox Code Playgroud)

执行的值初始化make_unique会将这 100 个字节归零,这是完全没有必要的,因为无论如何您都会立即覆盖它。

meow_for_overwrite函数改为执行默认初始化,因为无论如何都会立即覆盖所使用的内存(因此得名) - 也就是说等效于执行new T(没有任何括号或大括号)。我之前提到的那些情况下的默认初始化(如intand char、它们的数组和它们的聚合)不执行初始化,从而节省了时间。


对于具有用户提供的默认构造函数的类类型,值初始化和默认初始化之间没有区别:两者都只会调用默认构造函数。但是对于许多其他类型,可能会有很大的不同。