Std::unique_ptr支持数组,例如:

std::unique_ptr<int[]> p(new int[10]);

但这是必要的吗?可能使用std::vector或std::array更方便。

你觉得这个结构有什么用处吗?


当前回答

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[]>是初始化一个在编译时不知道大小的空数组的唯一方法。对于使用std::unique_ptr<T[]>的动机,Scott Meyers会说些什么呢?

其他回答

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[]>是初始化一个在编译时不知道大小的空数组的唯一方法。对于使用std::unique_ptr<T[]>的动机,Scott Meyers会说些什么呢?

std::vector可以被复制,而unique_ptr<int[]>允许表示数组的唯一所有权。另一方面,Std::array要求在编译时确定大小,这在某些情况下可能是不可能的。

在一些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...
...

unique_ptr<char[]>可以用在你想要C的性能和c++的便利性的地方。假设您需要操作数百万(好吧,如果您还不相信,则需要操作数十亿)字符串。将它们分别存储在单独的string或vector<char>对象中对于内存(堆)管理例程来说是一场灾难。特别是当您需要多次分配和删除不同的字符串时。

但是,您可以为存储这么多字符串分配一个缓冲区。你不会喜欢char* buffer = (char*)malloc(total_size);出于显而易见的原因(如果不明显,搜索“为什么使用智能ptrs”)。unique_ptr<char[]> buffer(new char[total_size]);

通过类比,同样的性能和便利性考虑也适用于非字符数据(考虑数百万个向量/矩阵/对象)。

如果您需要一个不可复制构造的对象的动态数组,那么可以使用一个指向数组的智能指针。例如,如果您需要一个原子数组怎么办?