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更方便。
你觉得这个结构有什么用处吗?
当前回答
与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());
}
其他回答
简而言之:它是迄今为止最节省内存的。
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.
最大的缺点是,每次我想知道字符串的长度,我必须调用strlen。
允许和使用std::unique_ptr<T[]>的另一个原因是,到目前为止还没有在响应中提到:它允许向前声明数组元素类型。
当您希望最小化头文件中的链式#include语句(以优化构建性能)时,这非常有用。
例如:
myclass.h:
class ALargeAndComplicatedClassWithLotsOfDependencies;
class MyClass {
...
private:
std::unique_ptr<ALargeAndComplicatedClassWithLotsOfDependencies[]> m_InternalArray;
};
myclass.cpp:
#include "myclass.h"
#include "ALargeAndComplicatedClassWithLotsOfDependencies.h"
// MyClass implementation goes here
使用上面的代码结构,任何人都可以#include " MyClass .h"并使用MyClass,而不必包括MyClass::m_InternalArray所要求的内部实现依赖。
如果m_InternalArray被声明为std::array< alargeandcomplatedclasswithlotsofdependencies >,或者std::vector<…> -结果将尝试使用不完整的类型,这是一个编译时错误。
std::vector可以被复制,而unique_ptr<int[]>允许表示数组的唯一所有权。另一方面,Std::array要求在编译时确定大小,这在某些情况下可能是不可能的。
这里有权衡,您可以选择与您想要的匹配的解决方案。我能想到的是:
初始大小
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[]>不是容器
我不得不承认,对于基于策略的设计来说,这似乎是一个重构的机会。
在一些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...
...