fen*_*fen 219 c++ smart-pointers c++11
std::unique_ptr
支持数组,例如:
std::unique_ptr<int[]> p(new int[10]);
Run Code Online (Sandbox Code Playgroud)
但它需要吗?可能使用std::vector
或更方便std::array
.
你觉得这个结构有用吗?
Nic*_*las 237
std::vector
即使有分配器,有些人也没有使用的奢侈品.有些人需要一个动态大小的数组,所以std::array
出来了.有些人从其他已知返回数组的代码中获取数组; 并且该代码不会被重写以返回a vector
或者某个东西.
通过允许unique_ptr<T[]>
,您可以满足这些需求.
简而言之,您可以unique_ptr<T[]>
在需要时使用.当替代品根本不适合你.这是最后的工具.
Pse*_*nym 115
有权衡,你选择符合你想要的解决方案.脱离我的头顶:
初始大小
vector
并unique_ptr<T[]>
允许在运行时指定大小array
只允许在编译时指定大小调整
array
并且unique_ptr<T[]>
不允许调整大小vector
不存储
vector
并将unique_ptr<T[]>
数据存储在对象外部(通常在堆上)array
将数据直接存储在对象中仿形
array
并vector
允许复制unique_ptr<T[]>
不允许复制交换/移动
vector
并unique_ptr<T[]>
有O(1)时间swap
和移动操作array
有O(n)时间swap
和移动操作,其中n是数组中元素的数量指针/引用/迭代器失效
array
确保指针,引用和迭代器永远不会在对象生效时失效,即使在 swap()
unique_ptr<T[]>
没有迭代器; 指针和引用仅swap()
在对象生效时失效.(交换后,指针指向您交换的数组,因此它们在这个意义上仍然"有效".)vector
可能会在任何重新分配时使指针,引用和迭代器无效(并提供一些保证重新分配只能在某些操作上发生).与概念和算法的兼容性
array
并且vector
都是容器unique_ptr<T[]>
不是容器我不得不承认,这似乎是对基于策略的设计进行重构的机会.
Cha*_*via 65
您可能使用a的一个原因unique_ptr
是,如果您不想支付初始化数组的运行时成本.
std::vector<char> vec(1000000); // allocates AND value-initializes 1000000 chars
std::unique_ptr<char[]> p(new char[1000000]); // allocates storage for 1000000 chars
Run Code Online (Sandbox Code Playgroud)
该std::vector
构造函数和std::vector::resize()
将值初始化T
-但new
不会做,如果T
是一个POD.
请参阅C++ 11和std :: vector构造函数中的Value-Initialized Objects
注意,vector::reserve
这里不是替代方法:在std :: vector :: reserve safe之后访问原始指针吗?
这是同样的原因,C程序员可能选择malloc
了calloc
.
And*_*owl 30
一个std::vector
可以复制的周围,同时unique_ptr<int[]>
允许表达阵列的唯一所有权.std::array
另一方面,要求在编译时确定大小,这在某些情况下可能是不可能的.
new*_*ing 22
Scott Meyers在Effective Modern C++中有这样的说法
的存在
std::unique_ptr
对数组应该只有智慧感兴趣的是你的,因为std::array
,std::vector
,std::string
几乎总是更好的数据结构的选择,要比原阵列.关于唯一可以想到的情况std::unique_ptr<T[]>
是,当你使用类似C的API时,它返回一个原始指针,指向你认为拥有的堆数组.
我认为Charles Salvia的答案是相关的:这std::unique_ptr<T[]>
是初始化一个空数组的唯一方法,该数组的大小在编译时是未知的.Scott Meyers对这种使用动机有什么看法std::unique_ptr<T[]>
?
geo*_*rge 14
与std::vector
和相反std::array
,std::unique_ptr
可以拥有一个NULL指针.
在使用期望数组或NULL的C API时,这会派上用场:
void legacy_func(const int *array_or_null);
void some_func() {
std::unique_ptr<int[]> ptr;
if (some_condition) {
ptr.reset(new int[10]);
}
legacy_func(ptr.get());
}
Run Code Online (Sandbox Code Playgroud)
小智 10
我曾经习惯于unique_ptr<char[]>
实现游戏引擎中使用的预分配内存池.我们的想法是提供预先分配的内存池而不是动态分配,用于返回碰撞请求结果和粒子物理等其他内容,而无需在每个帧分配/释放内存.对于这种需要内存池来分配具有有限生命周期(通常为一帧,两帧或三帧)且不需要破坏逻辑(仅内存释放)的对象的场景,这非常方便.
Vio*_*ffe 10
我不能强烈反对已接受答案的精神。“不得已的工具”?离得很远!
在我看来,与 C 和其他一些类似语言相比,C++ 最强大的特性之一是能够表达约束,以便在编译时检查它们并防止意外误用。因此,在设计结构时,问问自己它应该允许哪些操作。应该禁止所有其他用途,并且最好可以静态地(在编译时)实现此类限制,以便误用会导致编译失败。
因此,当需要一个数组时,以下问题的答案指定了它的行为: 1. 它的大小是 a) 在运行时是动态的,还是 b) 是静态的,但仅在运行时已知,或者 c) 是静态的并且在编译时已知?2. 数组是否可以在栈上分配?
根据答案,这就是我认为这种数组的最佳数据结构:
Dynamic | Runtime static | Static
Stack std::vector unique_ptr<T[]> std::array
Heap std::vector unique_ptr<T[]> unique_ptr<std::array>
Run Code Online (Sandbox Code Playgroud)
是的,我觉得unique_ptr<std::array>
也应该考虑,而且都不是万不得已的工具。想想什么最适合你的算法。
所有这些都可以通过原始指针到数据阵列与普通的C兼容的API(vector.data()
/ array.data()
/ uniquePtr.get()
)。
PS 除了上述考虑之外,还有一个所有权:std::array
和std::vector
具有值语义(具有对复制和按值传递的本机支持),而unique_ptr<T[]>
只能移动(强制单一所有权)。两者都可以在不同的场景中有用。相反,普通静态数组 ( int[N]
) 和普通动态数组 ( new int[10]
) 两者都不提供,因此应该尽可能避免 - 这在绝大多数情况下应该是可能的。如果这还不够,普通动态数组也无法查询它们的大小 - 内存损坏和安全漏洞的额外机会。
在一些 Windows Win32 API调用中可以找到一个常见的模式,其中使用std::unique_ptr<T[]>
可以派上用场,例如,当您在调用某些Win32 API(它会在内部写入一些数据)时,您并不确切知道输出缓冲区应该有多大缓冲区):
// Buffer dynamically allocated by the caller, and filled by some Win32 API function.
// (Allocation will be made inside the 'while' loop below.)
std::unique_ptr<BYTE[]> buffer;
// Buffer length, in bytes.
// Initialize with some initial length that you expect to succeed at the first API call.
UINT32 bufferLength = /* ... */;
LONG returnCode = ERROR_INSUFFICIENT_BUFFER;
while (returnCode == ERROR_INSUFFICIENT_BUFFER)
{
// Allocate buffer of specified length
buffer.reset( BYTE[bufferLength] );
//
// Or, in C++14, could use make_unique() instead, e.g.
//
// buffer = std::make_unique<BYTE[]>(bufferLength);
//
//
// Call some Win32 API.
//
// If the size of the buffer (stored in 'bufferLength') is not big enough,
// the API will return ERROR_INSUFFICIENT_BUFFER, and the required size
// in the [in, out] parameter 'bufferLength'.
// In that case, there will be another try in the next loop iteration
// (with the allocation of a bigger buffer).
//
// Else, we'll exit the while loop body, and there will be either a failure
// different from ERROR_INSUFFICIENT_BUFFER, or the call will be successful
// and the required information will be available in the buffer.
//
returnCode = ::SomeApiCall(inParam1, inParam2, inParam3,
&bufferLength, // size of output buffer
buffer.get(), // output buffer pointer
&outParam1, &outParam2);
}
if (Failed(returnCode))
{
// Handle failure, or throw exception, etc.
...
}
// All right!
// Do some processing with the returned information...
...
Run Code Online (Sandbox Code Playgroud)
简而言之:它是迄今为止最节省内存的.
A std::string
带有指针,长度和"短字符串优化"缓冲区.但我的情况是我需要存储一个几乎总是空的字符串,在一个我有成千上万的结构中.在C中,我只是使用char *
,大多数时候它都是null.这也适用于C++,除了a char *
没有析构函数,并且不知道要删除它自己.相反,std::unique_ptr<char[]>
当它超出范围时,它将自行删除.空std::string
占用32个字节,但空std::unique_ptr<char[]>
占用8个字节,即与其指针的大小完全相同.
最大的缺点是,每次我想知道字符串的长度时,我都要调用strlen
它.
我遇到了不得不使用std::unique_ptr<bool[]>
HDF5库(用于高效二进制数据存储的库,在科学上使用了很多)的情况。某些编译器(在我的情况下为std::vector<bool>
Visual Studio 2015)提供压缩(通过在每个字节中使用8个布尔值),这对于诸如HDF5之类的东西来说是灾难性的,它并不关心这种压缩。使用std::vector<bool>
,HDF5最终由于该压缩而读取垃圾。
猜猜谁在那儿进行救援,以防万一,std::vector
但是我没有必要分配一个动态数组?:-)
小智 6
允许和使用 的另一个原因std::unique_ptr<T[]>
,到目前为止尚未在响应中提及:它允许您向前声明数组元素类型。
当您想最小化#include
标头中的链式语句(以优化构建性能)时,这很有用。
例如 -
我的类.h:
class ALargeAndComplicatedClassWithLotsOfDependencies;
class MyClass {
...
private:
std::unique_ptr<ALargeAndComplicatedClassWithLotsOfDependencies[]> m_InternalArray;
};
Run Code Online (Sandbox Code Playgroud)
我的类.cpp:
#include "myclass.h"
#include "ALargeAndComplicatedClassWithLotsOfDependencies.h"
// MyClass implementation goes here
Run Code Online (Sandbox Code Playgroud)
有了上面的代码结构,任何人都可以#include "myclass.h"
和使用MyClass
,而不必包含MyClass::m_InternalArray
.
如果m_InternalArray
分别声明为 astd::array<ALargeAndComplicatedClassWithLotsOfDependencies>
或 a std::vector<...>
,结果将是尝试使用不完整的类型,这是编译时错误。
归档时间: |
|
查看次数: |
132995 次 |
最近记录: |