Std::unique_ptr支持数组,例如:
std::unique_ptr<int[]> p(new int[10]);
但这是必要的吗?可能使用std::vector或std::array更方便。
你觉得这个结构有什么用处吗?
Std::unique_ptr支持数组,例如:
std::unique_ptr<int[]> p(new int[10]);
但这是必要的吗?可能使用std::vector或std::array更方便。
你觉得这个结构有什么用处吗?
当前回答
如果您需要一个不可复制构造的对象的动态数组,那么可以使用一个指向数组的智能指针。例如,如果您需要一个原子数组怎么办?
其他回答
当你只能通过一个现有的API(窗口消息或线程相关的回调参数)插入一个指针时,它们可能是正确的答案,这些指针在被“捕捉”到另一边后具有一定的生命周期,但与调用代码无关:
unique_ptr<byte[]> data = get_some_data();
threadpool->post_work([](void* param) { do_a_thing(unique_ptr<byte[]>((byte*)param)); },
data.release());
我们都希望事情对自己有利。c++是其他时候用的。
这里有权衡,您可以选择与您想要的匹配的解决方案。我能想到的是:
初始大小
vector和unique_ptr<T[]>允许在运行时指定大小 数组只允许在编译时指定大小
调整
array和unique_ptr<T[]>不允许调整大小 向量是
存储
vector和unique_ptr<T[]>将数据存储在对象之外(通常在堆上) 数组将数据直接存储在对象中
复制
数组和向量允许复制 unique_ptr<T[]>不允许复制
交换/移动
vector和unique_ptr<T[]>有O(1)次交换和移动操作 数组有O(n)次交换和移动操作,其中n是数组中元素的数量
指针/引用/迭代器失效
array ensures pointers, references and iterators will never be invalidated while the object is live, even on swap() unique_ptr<T[]> has no iterators; pointers and references are only invalidated by swap() 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和vector都是容器 unique_ptr<T[]>不是容器
我不得不承认,对于基于策略的设计来说,这似乎是一个重构的机会。
您可能使用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
// C++20 version:
auto p = std::make_unique_for_overwrite<char[]>(1000000);
std::vector构造函数和std::vector::resize()将对t进行值初始化,但new和std::make_unique_for_overwrite将默认初始化它们,这对于PODs来说意味着什么都不做。
参见c++ 11中的值初始化对象和std::vector构造函数
注意,vector::reserve在这里不是一个替代方案:在std::vector::reserve之后访问原始指针是安全的吗?
这和C程序员选择malloc而不是calloc的原因是一样的。
unique_ptr<char[]>可以用在你想要C的性能和c++的便利性的地方。假设您需要操作数百万(好吧,如果您还不相信,则需要操作数十亿)字符串。将它们分别存储在单独的string或vector<char>对象中对于内存(堆)管理例程来说是一场灾难。特别是当您需要多次分配和删除不同的字符串时。
但是,您可以为存储这么多字符串分配一个缓冲区。你不会喜欢char* buffer = (char*)malloc(total_size);出于显而易见的原因(如果不明显,搜索“为什么使用智能ptrs”)。unique_ptr<char[]> buffer(new char[total_size]);
通过类比,同样的性能和便利性考虑也适用于非字符数据(考虑数百万个向量/矩阵/对象)。
在一些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...
...