使用std :: make_unique自定义初始化数组

时间:2018-04-08 23:46:49

标签: c++ unique-ptr

说我想创建std::unique_ptr<int[]>,但我想将创建的数组初始化为自定义值:{1,2,3,4,5}

我可以使用new并将原始指针传递给std::unique_ptr构造函数,然后构造函数将拥有并管理它。

std::unique_ptr<int[]> ptr{ new int[5]{1,2,3,4,5} };

我的问题是,可以用std::make_unique以某种方式完成同样的工作吗?

2 个答案:

答案 0 :(得分:3)

hgminh's answer(特别是推荐vector的部分,如果可能的话)是正确的,但我只想添加其他选项。

如果数组边界是已知且已修复的,而不是未知的绑定可变长度C样式数组,则可以从C样式数组切换到std::array来实现此目的。在完全启用优化的情况下,运行时工作是等效的(在-O1g++,它正确地确定它可以内联整个事物,使其成为普通分配,然后填充单个元素直接新分配的内存,而不是尝试在堆栈上创建array,然后将其作为参数传递给make_unique,这最终会调用移动构造函数,从而有效地使{{1}的工作倍增}})。你只需改变:

std::array<POD type>

为:

std::unique_ptr<int[]> ptr{ new int[5]{1,2,3,4,5} };

可悲的是,使用当前的非实验性功能集,这确实需要重复指定所指向的类型(一次构造它,一次定义模板化的auto ptr = std::make_unique<std::array<int, 5>>(std::array<int, 5>{1,2,3,4,5}); 类型),因为make_unique没有不接受初始化列表,所以你必须在语法上构造一个临时的,即使优化器避免它。对于这种特殊情况,您可以使用experimental features来避免重复自己,但它并不是更漂亮(如果您不使用make_unique语句来避免指定名称空间,实际上更长):

using

auto ptr = std::make_unique<std::array<int, 5>>(std::experimental::make_array(1,2,3,4,5)); 优于C风格数组的主要优点和缺点是无论哪种方式,最终结果为std::array,而不是std::unique_ptr<std::array<int, 5>>;一方面,指向的数组的大小永远不会改变(以后不能用指向std::unique_ptr<int[]>的指针替换unique_ptr内容),但另一方面,大小是在编译时烘焙,因此您和编译器都知道的大小。

由于编译器知道大小,因此在调用在其参数类型上模板化的函数时,您不必手动传递指针和大小。该模板将编译时专门用于您的精确大小(这允许编译器在循环展开或使用常量循环边界时进行更好的优化选择)而不会传递大小。

对于未模板化且期望C风格参数的函数(例如,他们期望一个数组,并且接收第一个元素的std::array<int, 6>int*的长度),您只需传递{{1} }作为指针,size_t作为长度。由于大小是编译时常量,因此可以免费获得DRY(不会在多个位置重复数组的大小,也不仅仅为了避免DRY而定义相当无用的命名常量;大小是类型定义,内联使用,在上下文中具有明显的意义),没有性能开销(它应该内联到编译时间大小,就像你自己键入大小一样,但是如果{{1}没有数字失去同步的风险稍后会改变大小。)

再次,绝对清楚,这里的正确答案几乎总是“使用&ptr[0],基本上是ptr->size()

  1. 根据需要自动调整array的大小
  2. 简化的常见用例
  3. 当没有主动更改大小时,std::vector<int>可以与C风格的数组API一起使用(通过std::unique_ptr<int[]> / int[] / std::vector作为指针并且vec.data()作为长度),并且您不必担心管理调整大小/重新分配(当您无法使用&vec[0]而不放弃{{1}的访问权限时,这是C ++的痛苦}})。从理论上讲,它可以慢一点 tiny ,但在99%的情况下,它会比任何必须重新实现&vec.at(0)的事情更快 - 就像从头开始的行为一样(因为vec.size()被调整为以最大速度“正常工作”,而您自己的代码不太可能经过仔细调整。)

答案 1 :(得分:1)

std::make_unique有3次重载:

template< class T, class... Args >
unique_ptr<T> make_unique( Args&&... args );     // (1) for non-array type

template< class T >
unique_ptr<T> make_unique( std::size_t size );   // (2) for array type with unknown bounds

template< class T, class... Args >
/* unspecified */ make_unique( Args&&... args ) = delete; // (3) for array type with known bounds.

它们都不支持您想要的行为(请注意第三个函数标记为delete)。

您可以使用(2)分别初始化数组元素,或切换到std::vector并使用(1)。