std::make_unique_for_overwrite() 对 std::make_unique() 有什么作用?



似乎在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);

std::shared_ptrstd::make_shared也是如此.为什么现有函数不是:

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

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

注意:在这些功能的早期提案中,名称make_unique_default_init()

这些新功能不同的:

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

这是普通指针的一个功能,智能指针实用程序函数不提供: 使用常规指针,您可以只分配而无需实际初始化指向的值:

new int

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

std::unique_ptr<int[]>(new int[n])

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

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

allocate_sharedmake_sharedmake_unique都通过执行等效于new T(args...)的操作来初始化底层对象。在零参数的情况下,这减少到new T()- 也就是说,它执行值初始化。在许多情况下,值初始化(包括标量类型,如intchar,它们的数组和它们的聚合(执行零初始化- 也就是说,这是为清零一堆数据所做的实际工作。

也许你想要那个,这对你的应用程序很重要,也许你不需要。从P1020R1年开始,介绍函数的论文最初命名为make_unique_default_initmake_shared_default_initallocate_shared_default_init(在C++20的全国投票评论过程中,这些函数从meow_default_init重命名为meow_for_overwrite(:

内置

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

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

auto buffer = std::make_unique<char[]>(100);
read_data_into(buffer.get());

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

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


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

相关内容

  • 没有找到相关文章

最新更新