C++ 什么时候应该使用智能指针来保存数组?
我看到许多答案建议使用智能指针在内存中保存动态分配的数组。我的观点一直是,如果已知大小,则应将其包装在C++ 什么时候应该使用智能指针来保存数组?,c++,c++11,C++,C++11,我看到许多答案建议使用智能指针在内存中保存动态分配的数组。我的观点一直是,如果已知大小,则应将其包装在std::array中,同样,如果大小未知(即,通过将智能指针的指针类型设置为未知绑定的数组,并reset(),稍后将其重置),则应使用std::vector。事实上,我一直都是这样做的 例如,最近我看到一个答案使用了std::unique\u ptr p(new int[5])。这似乎类似于构造一个std::array,因为大小是已知的。此外,附加的好处是std::array静态分配其数组,并
std::array
中,同样,如果大小未知(即,通过将智能指针的指针类型设置为未知绑定的数组,并reset()
,稍后将其重置),则应使用std::vector
。事实上,我一直都是这样做的
例如,最近我看到一个答案使用了std::unique\u ptr p(new int[5])
。这似乎类似于构造一个std::array
,因为大小是已知的。此外,附加的好处是std::array
静态分配其数组,并包含类似数组的特性,如大小、迭代器等
那么,与使用其他专门为此目的而设计的标准容器相比,使用智能指针来保存数组的原因是什么呢?当您知道运行时的时间时,可以使用指向数组的唯一指针,但它不会改变,这保证了您将只为这些对象分配空间,而不会再为其他对象分配空间。对于向量,您可以在内部分配更多空间,这是实现定义的,但为了有良好的插入摊销时间,它通常在每次增长向量时分配至少两倍的所需空间,因为它需要复制。首先,
unique\u ptr
不需要静态大小-它可以是unique\u ptr
此外,额外的好处是std::array静态分配
它的数组
这并不能严格保证是一种利益。考虑一下,如果我有一个10兆字节的数组,那它就要炸毁我的栈。
一般来说,当人们希望数组大小在创建时固定,但能够变异成员时,他们会选择这种方法。请注意,对于
std::vector
,只能同时生成元素和vector
常量,或者两者都不能。您不能只生成向量而不生成元素const在std::vector
和std::array
之间进行简单的权衡:“大小总是一样吗?”
然后,“我是否需要智能指针”的决定对于任何其他类型都是相同的。是否要将其作为共享对象传递?使用std::shared\u ptr
。我想在不复制的情况下传递一个大对象吗?使用std::unique\u ptr
假设您有一个2048缓冲区,您希望在程序中传递它,但不会引入很多副本。您可以使用std::shared\u ptr
。正如您所说,std::array
是一个静态数组。如果在堆栈上声明std::array
,则实际数组位于堆栈上。而std::unique_ptr(new int[5])
将实际数组放在堆上。对于小型阵列来说,这似乎不是一个很大的区别,但对于大型阵列来说,这是一个很大的区别。仅仅因为数组的长度是固定的,并不意味着它应该总是在堆栈上。它取决于数组的大小和可用堆栈空间的大小。在堆栈上放置大型数组有引发堆栈溢出错误的风险。在堆上放置大型数组不会抛出该错误(除非堆栈已满,因此分配数组后无法构建unique_ptr
),但如果堆/memmgr已满,抛出内存不足错误的风险较小,但是,在构建Unique\ptr
之前,就会发生这种情况。数组的智能指针就是智能指针。因此,您应该在适当使用智能指针的地方使用它们
与遗留代码交互
假设您有一个遗留的代码库,该代码库带有一个函数,该函数创建了一个数组,您必须在以后delete[]
。如何使此代码异常安全?简单,将其存储在智能指针中
stuff* legacy_function();
// ...
std::unique_ptr<stuff[]> arr(legacy_function());
stuff*legacy_函数();
// ...
std::unique_ptr arr(遗留_函数());
类似场景:遗留功能希望拥有阵列的所有权:
std::unique_ptr<stuff[]> arr(new stuff[20]);
// do operations, possibly exception-throwing
other_legacy_function(arr.release());
std::unique_ptr arr(新材料[20]);
//执行操作,可能是异常抛出
其他旧功能(arr.release());
试着用std::vector
这样做
虽然正确的解决方案是更改您的设计,但您不这么做可能有社会和实际原因(第三方代码?)。或者,也许你正在一步一步地重构代码
实现容器
没有理由不能在std::unique\u ptr
之上实现容器。我看不出为什么编写手工容器的人不能从现有的“策略处理程序”中获益,而不是手动编写代码来满足三/五规则
总结
是的,你应该更喜欢集装箱。是的,std::unique_ptr
没有那么有用 不是unique_ptr
,而是shared_ptr
对于实现引用计数数组可能很有用。不要将智能指针视为自删除指针,而是从所有权的角度来看待它们。这一点很好,但这与在智能指针中保留std::array
有什么区别(除一个较低的间接层次外)?另一个问题是为什么他们使用unique\u ptr
而不是unique\u ptr
后者是有用的,与std::array
不同,它可以容纳编译时大小未知的数组,并且不会邀请人们尝试像std::vector
这样昂贵的大小更改操作。std::unique\u ptr p(new int[5])
甚至不应该编译,您正在传递一个int*
,其中构造函数需要一个指向大小为5的数组的指针。“它是实现定义的,但为了有良好的插入摊销时间,它通常会在每次增加向量时分配至少两倍的所需内容”不,不完全是