首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用std::make_unique自定义初始化数组

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

Stack Overflow用户
提问于 2018-04-08 23:46:48
回答 2查看 5.6K关注 0票数 9

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

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

代码语言:javascript
复制
std::unique_ptr<int[]> ptr{ new int[5]{1,2,3,4,5} };

我的问题是,std::make_unique也能做到同样的事情吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-04-09 02:17:45

std::make_unique有3个过载

代码语言:javascript
复制
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)。

票数 6
EN

Stack Overflow用户

发布于 2018-05-02 17:39:37

如果可能的话,vector hgminh的回答 (特别是推荐的部分)是正确的,但我只想添加另一个选项。

如果数组边界已知且固定,而不是未知绑定变量长度C样式数组,则可以从C样式数组切换到std::array以实现这一点。在启动优化之后,运行时的工作是等效的(在-O1g++中,它正确地确定它可以内联整个事情,使其成为一个简单的分配,然后直接填充新分配的内存中的各个元素,而不是试图在堆栈上生成一个array,然后将它作为参数传递给make_unique,后者最终会调用移动构造函数,有效地加倍了std::array<POD type>的工作)。你只需要改变一下:

代码语言:javascript
复制
std::unique_ptr<int[]> ptr{ new int[5]{1,2,3,4,5} };

至:

代码语言:javascript
复制
auto ptr = std::make_unique<std::array<int, 5>>(std::array<int, 5>{1,2,3,4,5});

遗憾的是,对于当前的非实验性特性集,这确实需要反复指定所指向的类型(一次来构造它,一次定义make_unique的模板类型),因为make_unique不接受初始化程序列表,所以您必须在语法上构造一个临时的,即使优化器避免了它。对于这种特殊情况,您可以使用实验特征来避免重复,但它并不是更漂亮(如果您不使用using语句来避免指定名称空间,实际上更长):

代码语言:javascript
复制
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[]>;一方面,所指向的数组的大小永远不会改变(您以后不能用指向std::array<int, 6>的指针替换unique_ptr内容),但是另一方面,这个大小是在编译时输入的,所以您和编译器都知道大小。

由于编译器知道大小,所以当调用参数类型上的模板函数时,不必手动传递指针和大小。模板将在编译时专门指定到您的精确大小(这允许编译器在循环展开或使用常数循环边界时做出更好的优化选择),而不需要传递大小。

对于没有模板化并期望C风格参数的函数(例如,它们期望一个数组,并接收第一个元素的int*和长度的size_t ),您只需传递&ptr[0]作为指针,ptr->size()作为长度。由于大小是一个编译时间常数,因此可以免费获得干的 (不能在多个地方重复数组的大小,也不是仅仅为了避免干燥而定义相当无用的命名常量;大小是类型定义的一部分,在上下文中有明显的意义),没有性能开销(它应该与编译时大小内联,就像您自己键入大小一样,但是如果以后更改array's的大小,则不会出现数字不同步的风险)。

再说一遍,要说得非常清楚,这里的正确答案几乎总是“使用类似于std::vector<int>**"**,的 std::unique_ptr<int[]>

  1. 根据需要自动调整int[]大小
  2. 极大地简化了通用用例(例如初始化、复制、移动等)。

当大小未被主动更改时,std::vector可以与C风格的数组API一起使用(将std::vector作为指针传递,vec.size()作为长度传递),您不需要担心管理调整大小/重新分配(如果不放弃对delete[]的访问,就无法使用realloc时,这在C++中是一个难题)。从理论上讲,它可以稍微慢一点,但在99%的情况下,它将比从头开始重新实现vector-like行为的任何事情都要快(因为vector被调到“只是以最快的速度工作”,而您自己的代码不太可能被仔细调优)。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49723917

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档