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

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

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

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


当前回答

医生:这是穷人的性病。

让我们把std::unique_ptr<T[]>看作一个容器。实际上,由于缺少size字段,不能直接作为容器使用,它在标准库中可用的容器的“参数空间”中占据了一个点,而这个点不被其他合适的容器共享——即使在混合中添加Boost也不行。

如果你看看我对广泛可用的类向量/连续容器的比较,并寻找与std::unique_ptr相同的特性:

堆上的分配 容量在编译时不固定 在建造后不能改变容量(没有完全清理集装箱)

你会发现除了std::dynarray,没有其他容器提供所有这些;但它实际上不在标准库中——它本应被纳入c++ 14,但最终被拒绝了。

我不仅仅是在猜测。甚至在《SO》中,人们也偶尔这样描述事物;参见@KerrekSB 2013年对这个问题的回答。

其他回答

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

允许和使用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<…> -结果将尝试使用不完整的类型,这是一个编译时错误。

出于二进制兼容性的考虑,您需要结构只包含一个指针。 你需要使用一个API来返回用new[]分配的内存 例如,您的公司或项目有一个禁止使用std::vector的一般规则,以防止粗心的程序员不小心引入副本 您希望防止粗心的程序员在这种情况下意外地引入副本。

有一个普遍的规则,c++容器比使用指针滚动自己的容器更受欢迎。这是一个普遍规律;它有例外。有更多的;这些只是例子。

为了回答人们认为你“必须”使用vector而不是unique_ptr,我在GPU上的CUDA编程中有一个案例,当你在Device中分配内存时,你必须使用一个指针数组(使用cudaMalloc)。 然后,当在Host中检索该数据时,必须再次寻找指针,unique_ptr可以很容易地处理指针。 将double*转换为vector<double>的额外成本是不必要的,并且会导致性能损失。

与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());
}