应该何时使用智能指针来保存数组?

时间:2014-09-06 14:41:05

标签: c++ c++11

我看到很多答案建议使用智能指针在内存中保存动态分配的数组。我的观点一直是,如果大小已知,它应该包含在std::array中,同样如果大小未知(即通过使智能指针的指针类型为未知边界的数组而且{ {1}}稍后再进行此操作)应使用reset()。事实上,这就是我经常做的事情。

例如,最近我看到了一个使用std::vector的答案。这似乎类似于构造std::unique_ptr<int[5]> p(new int[5]),因为已知大小。此外,额外的好处是std::array<int, 5>静态分配其数组并包含类似数组的特性,如大小,迭代器等。

那么使用智能指针来保持数组而不是使用专门为此目的而制作的其他标准容器的原因是什么?

5 个答案:

答案 0 :(得分:2)

首先,unique_ptr<T[]>不需要静态大小 - 它可以只是unique_ptr<int[]>

  

此外,额外的好处是std :: array静态分配   它的数组

这并非严格保证是的好处。考虑一下,如果我有一个10兆字节的阵列 - 那将会破坏我的筹码。

一般来说,当人们希望在创建时修复数组大小但是能够改变成员时,人们会选择这种方法。请注意,对于std::vector,您只能 元素 vector const,或两者都不。您不能只制作矢量而不能制作元素const

答案 1 :(得分:1)

正如你所说,std::array是一个静态数组。如果在堆栈上声明std::array<int, 5>,则实际数组在堆栈上。而std::unique_ptr<int[]>(new int[5])将实际数组放在堆上。对于小型阵列来说,这似乎不是一个很大的区别,但对于大型阵列来说这是一个大问题。仅仅因为数组是固定长度并不意味着它应该总是在堆栈上。它取决于数组的大小和可用的堆栈空间。在堆栈上放置一个大型数组可能会导致堆栈溢出错误。在堆上放置一个大型数组不会抛出它(除非堆栈已满,因此在分配数组后无法构造unique_ptr),尽管它确实存在抛出内存不足错误的风险较小堆/ memmgr已满,但这会在构造Unique_ptr之前发生。

答案 2 :(得分:0)

当您知道运行时的时间时,您可以使用指向数组的唯一指针,但它不会更改,这可以保证您只为这些对象分配空间而不再有空间。使用向量,您可以在内部分配更多空间,它是实现定义的,但为了具有良好的插入分摊时间,它通常至少分配它每次增长向量时所需的两倍,因为它需要复制。

答案 3 :(得分:0)

std::vectorstd::array之间的权衡很简单:&#34;大小始终相同?&#34;。

然后决定&#34;我是否想要一个智能指针&#34;对于任何其他类型都是相同的。我想将它作为共享对象传递吗?使用std::shared_ptr。我想传递一个大对象而不制作副本吗?使用std::unique_ptr

假设您有一个2048缓冲区要在程序中传递,但不会引入多个副本。您可以使用std::shared_ptr<std::array<unsigned char, 2048>>

答案 4 :(得分:0)

数组的智能指针就是 - 智能指针。因此,您应该在智能指针使用合适的地方使用它们。

与遗留代码交互

假设您的遗留代码库具有一个函数,该函数可以创建一个稍后必须delete[]的数组。您将如何使此代码异常安全?简单,将其存储在智能指针中。

stuff* legacy_function();
// ...
std::unique_ptr<stuff[]> arr(legacy_function());

类似的情况:遗留函数需要数组的所有权:

std::unique_ptr<stuff[]> arr(new stuff[20]);
// do operations, possibly exception-throwing
other_legacy_function(arr.release());

尝试使用std::vector执行

虽然正确的解决方案是改变您的设计,但可能存在社会和实际原因,为什么您不会这样做(第三方代码?)。或者,也许你一步一步重构代码?

实施容器

没有理由在std::unique_ptr之上无法实施容器。我认为没有理由为什么编写手工制作的容器的人不能从现有的政策处理人员那里受益。而不是手动编写代码以满足三/五规则。

摘要

是的,您应该更喜欢容器。是的,std::unique_ptr<T[]> 非常有用。