std :: make_unique_default_init()有什么作用? std :: make_unique()是否冗余?

时间:2019-09-22 15:49:45

标签: c++ smart-pointers c++20

在C ++ 20中,我们似乎获得了一些用于智能指针的附加实用程序功能,包括:

template<class T> unique_ptr<T> make_unique_default_init();
template<class T> unique_ptr<T> make_unique_default_init(size_t n);

,与std::make_sharedstd::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);

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

2 个答案:

答案 0 :(得分:3)

这些新功能 不同:

  • 原始make_XYZ始终初始化指向的值(“显式初始化”,请参见standard中的§class.expl.init)。
  • 新的make_XYZ_default_init:对指向的值执行“默认初始化”(请参见standard中的dcl.init,第7段);这意味着对于典型计算机上的非类,非数组类型,实际上没有初始化。 (是的,这个术语有点令人困惑。)

这是普通香草指针的功能,而智能指针实用程序功能不具备此功能:使用常规指针,您可以分配而无需实际初始化指向的值:

T* my_ptr { new int };

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

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

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

注意:请参阅相关的ISO C ++ WG21 proposalthis SO answer

答案 1 :(得分:2)

allocate_sharedmake_sharedmake_unique都通过执行等效于new T(args...)的操作来初始化基础对象。在零参数的情况下,它减少为new T()-也就是说,它执行value initialization。在许多情况下,值初始化(包括诸如intchar的标量类型,它们的数组以及它们的集合)会执行zero initialization-也就是说,这实际上是为了完成将一堆数据归零。

也许您想要那样,那对您的应用程序很重要,也许您不需要。在P1020R1中,介绍了make_unique_default_initmake_shared_default_initallocate_shared_default_init的论文:

  

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

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

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

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

新的meow_default_init函数改为执行default initialization(因此得名)-也就是说,相当于执行new T(不带括号或花括号)。在我前面提到的那些情况下,默认初始化(例如intchar,它们的数组以及它们的集合)不执行任何初始化,从而节省了时间。


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

相关问题