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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 20:34:56  来源:igfitidea点击:

Is there any use for unique_ptr with array?

c++c++11smart-pointersunique-ptr

提问by fen

std::unique_ptrhas 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::vectoror std::array.

但有必要吗?可能使用std::vectoror更方便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::arrayis 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 vectoror 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

初始尺寸

  • vectorand unique_ptr<T[]>allow the size to be specified at run-time
  • arrayonly allows the size to be specified at compile time
  • vectorunique_ptr<T[]>允许在运行时指定大小
  • array只允许在编译时指定大小

Resizing

调整大小

  • arrayand unique_ptr<T[]>do not allow resizing
  • vectordoes
  • array并且unique_ptr<T[]>不允许调整大小
  • vector

Storage

贮存

  • vectorand unique_ptr<T[]>store the data outside the object (typically on the heap)
  • arraystores the data directly in the object
  • vector并将unique_ptr<T[]>数据存储在对象之外(通常在堆上)
  • array将数据直接存储在对象中

Copying

复印

  • arrayand vectorallow copying
  • unique_ptr<T[]>does not allow copying
  • arrayvector允许复制
  • unique_ptr<T[]>不允许复制

Swap/move

交换/移动

  • vectorand unique_ptr<T[]>have O(1) time swapand move operations
  • arrayhas O(n) time swapand 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

指针/引用/迭代器失效

  • arrayensures 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.)
  • vectormay 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

与概念和算法的兼容性

  • arrayand vectorare both Containers
  • unique_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_ptris 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::vectorconstructor and std::vector::resize()will value-initialize T- but newwill not do that if Tis 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::reserveis 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 mallocover calloc.

这是同样的原因,C程序员可能选择malloccalloc

回答by Andy Prowl

An std::vectorcan 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_ptrfor arrays should be of only intellectual interest to you, because std::array, std::vector, std::stringare virtually always better data structure choices than raw arrays. About the only situation I can conceive of when a std::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::arraystd::vectorstd::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::vectorand std::array, std::unique_ptrcan own a NULL pointer.
This comes in handy when working with C APIs that expect either an array or NULL:

std::vectorand相反std::arraystd::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::stringcomes 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::stringtakes 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 strlenon 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::vectordidn't work, and I needed to allocate a dynamic array cleanly? :-)

猜猜谁在那里救援,在std::vector没有工作的情况下,我需要干净地分配一个动态数组?:-)