C++ unique_ptr 与数组有什么用处吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16711697/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there any use for unique_ptr with array?
提问by fen
std::unique_ptr
has support for arrays, for instance:
std::unique_ptr
支持数组,例如:
std::unique_ptr<int[]> p(new int[10]);
but is it needed? probably it is more convenient to use std::vector
or std::array
.
但有必要吗?可能使用std::vector
or更方便std::array
。
Do you find any use for that construct?
你觉得那个构造有什么用吗?
回答by Nicol Bolas
Some people do not have the luxury of using std::vector
, even with allocators. Some people need a dynamically sized array, so std::array
is out. And some people get their arrays from other code that is known to return an array; and that code isn't going to be rewritten to return a vector
or something.
有些人甚至没有使用std::vector
分配器的奢侈。有些人需要一个动态大小的数组,所以std::array
就不行了。有些人从其他已知返回数组的代码中获取他们的数组;并且该代码不会被重写以返回一个vector
或其他东西。
By allowing unique_ptr<T[]>
, you service those needs.
通过允许unique_ptr<T[]>
,您可以满足这些需求。
In short, you use unique_ptr<T[]>
when you needto. When the alternatives simply aren't going to work for you. It's a tool of last resort.
简而言之,您unique_ptr<T[]>
在需要时使用。当替代方案根本不适合您时。这是最后的手段。
回答by Pseudonym
There are tradeoffs, and you pick the solution which matches what you want. Off the top of my head:
有一些权衡,您可以选择与您想要的解决方案相匹配的解决方案。在我的头顶:
Initial size
初始尺寸
vector
andunique_ptr<T[]>
allow the size to be specified at run-timearray
only allows the size to be specified at compile time
vector
并unique_ptr<T[]>
允许在运行时指定大小array
只允许在编译时指定大小
Resizing
调整大小
array
andunique_ptr<T[]>
do not allow resizingvector
does
array
并且unique_ptr<T[]>
不允许调整大小vector
做
Storage
贮存
vector
andunique_ptr<T[]>
store the data outside the object (typically on the heap)array
stores the data directly in the object
vector
并将unique_ptr<T[]>
数据存储在对象之外(通常在堆上)array
将数据直接存储在对象中
Copying
复印
array
andvector
allow copyingunique_ptr<T[]>
does not allow copying
array
并vector
允许复制unique_ptr<T[]>
不允许复制
Swap/move
交换/移动
vector
andunique_ptr<T[]>
have O(1) timeswap
and move operationsarray
has O(n) timeswap
and move operations, where n is the number of elements in the array
vector
并且unique_ptr<T[]>
有 O(1) 时间swap
和移动操作array
有 O(n) 次时间swap
和移动操作,其中 n 是数组中的元素数
Pointer/reference/iterator invalidation
指针/引用/迭代器失效
array
ensures pointers, references and iterators will never be invalidated while the object is live, even onswap()
unique_ptr<T[]>
has no iterators; pointers and references are only invalidated byswap()
while the object is live. (After swapping, pointers point into to the array that you swapped with, so they're still "valid" in that sense.)vector
may invalidate pointers, references and iterators on any reallocation (and provides some guarantees that reallocation can only happen on certain operations).
array
确保指针、引用和迭代器在对象处于活动状态时永远不会失效,即使在swap()
unique_ptr<T[]>
没有迭代器;指针和引用仅swap()
在对象处于活动状态时失效。(交换后,指针指向与您交换的数组,因此在这个意义上它们仍然是“有效的”。)vector
可能会使任何重新分配的指针、引用和迭代器无效(并提供一些保证,重新分配只能发生在某些操作上)。
Compatibility with concepts and algorithms
与概念和算法的兼容性
array
andvector
are both Containersunique_ptr<T[]>
is not a Container
array
并且vector
都是容器unique_ptr<T[]>
不是容器
I do have to admit, this looks like an opportunity for some refactoring with policy-based design.
我不得不承认,这看起来像是使用基于策略的设计进行一些重构的机会。
回答by Charles Salvia
One reason you might use a unique_ptr
is if you don't want to pay the runtime cost of value-initializingthe array.
您可能使用 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
The std::vector
constructor and std::vector::resize()
will value-initialize T
- but new
will not do that if T
is a POD.
该std::vector
构造函数和std::vector::resize()
将值初始化T
-但new
不会做,如果T
是一个POD。
See Value-Initialized Objects in C++11 and std::vector constructor
请参阅C++11 中的值初始化对象和 std::vector 构造函数
Note that vector::reserve
is not an alternative here: Is accessing the raw pointer after std::vector::reserve safe?
请注意,vector::reserve
这里不是替代方案:在 std::vector::reserve 之后访问原始指针是否安全?
It's the same reason a C programmer might choose malloc
over calloc
.
这是同样的原因,C程序员可能选择malloc
了calloc
。
回答by Andy Prowl
An std::vector
can be copied around, while unique_ptr<int[]>
allows expressing unique ownership of the array. std::array
, on the other hand, requires the size to be determined at compile-time, which may be impossible in some situations.
Anstd::vector
可以被复制,同时unique_ptr<int[]>
允许表达数组的唯一所有权。std::array
,另一方面,需要在编译时确定大小,这在某些情况下可能是不可能的。
回答by newling
Scott Meyers has this to say in Effective Modern C++
Scott Meyers 在 Effective Modern C++ 中有这样的说法
The existence of
std::unique_ptr
for arrays should be of only intellectual interest to you, becausestd::array
,std::vector
,std::string
are virtually always better data structure choices than raw arrays. About the only situation I can conceive of when astd::unique_ptr<T[]>
would make sense would be when you're using a C-like API that returns a raw pointer to a heap array that you assume ownership of.
的存在
std::unique_ptr
对数组应该只有智慧感兴趣的是你的,因为std::array
,std::vector
,std::string
几乎总是更好的数据结构的选择,要比原阵列。我能想到的唯一情况std::unique_ptr<T[]>
是,当您使用类似 C 的 API 时,该 API 返回指向您承担所有权的堆数组的原始指针。
I think that Charles Salvia's answer is relevant though: that std::unique_ptr<T[]>
is the only way to initialise an empty array whose size is not known at compile time. What would Scott Meyers have to say about this motivation for using std::unique_ptr<T[]>
?
我认为 Charles Salvia 的回答是相关的:这std::unique_ptr<T[]>
是初始化一个在编译时大小未知的空数组的唯一方法。Scott Meyers 对这种使用的动机有什么看法std::unique_ptr<T[]>
?
回答by george
Contrary to std::vector
and std::array
, std::unique_ptr
can own a NULL pointer.
This comes in handy when working with C APIs that expect either an array or NULL:
与std::vector
and相反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());
}
回答by Simon Ferquel
I have used unique_ptr<char[]>
to implement a preallocated memory pools used in a game engine. The idea is to provide preallocated memory pools used instead of dynamic allocations for returning collision requests results and other stuff like particle physics without having to allocate / free memory at each frame. It's pretty convenient for this kind of scenarios where you need memory pools to allocate objects with limited life time (typically one, 2 or 3 frames) that do not require destruction logic (only memory deallocation).
我曾经unique_ptr<char[]>
实现过在游戏引擎中使用的预分配内存池。这个想法是提供预先分配的内存池,而不是动态分配来返回碰撞请求结果和粒子物理等其他东西,而不必在每一帧分配/释放内存。对于需要内存池来分配生命周期有限(通常为 1、2 或 3 帧)且不需要销毁逻辑(仅内存释放)的对象的这种场景,这非常方便。
回答by Mr.C64
A common pattern can be found in someWindows Win32 APIcalls, in which the use of std::unique_ptr<T[]>
can come in handy, e.g. when you don't exactly know how big an output buffer should be when calling some Win32 API (that will write some data inside that buffer):
在一些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...
...
回答by jorgbrown
In a nutshell: it's by far the most memory-efficient.
简而言之:它是迄今为止内存效率最高的。
A std::string
comes with a pointer, a length, and a "short-string-optimization" buffer. But my situation is I need to store a string that is almost always empty, in a structure that I have hundreds of thousands of. In C, I would just use char *
, and it would be null most of the time. Which works for C++, too, except that a char *
has no destructor, and doesn't know to delete itself. By contrast, a std::unique_ptr<char[]>
will delete itself when it goes out of scope. An empty std::string
takes up 32 bytes, but an empty std::unique_ptr<char[]>
takes up 8 bytes, that is, exactly the size of its pointer.
Astd::string
带有一个指针、一个长度和一个“短字符串优化”缓冲区。但我的情况是我需要在一个结构中存储一个几乎总是空的字符串。在 C 中,我只会使用char *
,并且大部分时间它都是空的。这也适用于 C++,只是 achar *
没有析构函数,并且不知道删除自己。相比之下, astd::unique_ptr<char[]>
超出范围时将删除自身。一个空std::string
占用32个字节,而一个空std::unique_ptr<char[]>
占用8个字节,也就是正好是它的指针大小。
The biggest downside is, every time I want to know the length of the string, I have to call strlen
on it.
最大的缺点是,每次我想知道字符串的长度时,都必须调用strlen
它。
回答by The Quantum Physicist
I faced a case where I had to use std::unique_ptr<bool[]>
, which was in the HDF5 library (A library for efficient binary data storage, used a lot in science). Some compilers (Visual Studio 2015 in my case) provide compression of std::vector<bool>
(by using 8 bools in every byte), which is a catastrophe for something like HDF5, which doesn't care about that compression. With std::vector<bool>
, HDF5 was eventually reading garbage because of that compression.
我遇到了一个必须使用的情况std::unique_ptr<bool[]>
,它位于 HDF5 库(一个用于高效二进制数据存储的库,在科学中被大量使用)。一些编译器(在我的例子中是 Visual Studio 2015)提供压缩std::vector<bool>
(通过在每个字节中使用 8 个布尔值),这对于像 HDF5 这样的东西来说是一场灾难,它不关心这种压缩。使用std::vector<bool>
,由于这种压缩,HDF5 最终会读取垃圾。
Guess who was there for the rescue, in a case where std::vector
didn't work, and I needed to allocate a dynamic array cleanly? :-)
猜猜谁在那里救援,在std::vector
没有工作的情况下,我需要干净地分配一个动态数组?:-)