unique_ptr有数组的用法吗?

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

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

但是它需要? 可能使用std::vectorstd::array会更方便。

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

有些人并不喜欢使用std::vector ,即使是分配器也是如此。 有些人需要一个dynamic大小的数组,所以std::array已经不在了。 有些人从其他已知返回数组的代码中获取数组; 而且代码不会被重写为返回一个vector或其他东西。

通过允许unique_ptr<T[]> ,您可以满足这些需求。

总之,你需要的时候使用unique_ptr<T[]> 。 当替代品根本不会为你工作。 这是最后的手段。

有折衷,你select符合你想要的解决scheme。 closures我的头顶上:

初始大小

  • vectorunique_ptr<T[]>允许在运行时指定大小
  • array只允许在编译时指定大小

调整

  • arrayunique_ptr<T[]>不允许resize
  • vector

存储

  • vectorunique_ptr<T[]>将数据存储在对象之外(通常在堆上)
  • array直接将数据存储在对象中

仿形

  • arrayvector允许复制
  • unique_ptr<T[]>不允许复制

交换/移动

  • vectorunique_ptr<T[]>有O(1)次swap和移动操作
  • array有O(n)时间swap和移动操作,其中n是数组中元素的数量

指针/引用/迭代器失效

  • array确保指针,引用和迭代器不会在对象处于活动状态时失效,即使在swap()
  • unique_ptr<T[]>没有迭代器; 指针和引用仅在对象处于活动状态时才由swap()失效。 (交换之后,指针指向你交换的数组,所以它们在这个意义上仍然是“有效的”)。
  • vector可以使任何重新分配的指针,引用和迭代器无效(并且提供一些保证重新分配只能在某些操作上发生)。

与概念和algorithm兼容

  • arrayvector都是容器
  • unique_ptr<T[]>不是一个容器

我不得不承认,这看起来像是一个重构基于策略的devise的机会。

你可能会使用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 

std::vector构造函数和std::vector::resize()将会初始化T – 但是如果T是POD, new将不会这么做。

请参阅C ++ 11中的值初始化对象和std :: vector构造函数

请注意, vector::reserve不是这里的替代方法: 访问std :: vector :: reserve safe之后的原始指针?

C程序员可能会selectmalloc不是calloc

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

Scott Meyers在Effective Modern C ++中有这样的说法

数组的std::unique_ptr的存在应该只对你有兴趣,因为std::arraystd::vectorstd::string实际上总是比原始数组更好的数据结构select。 关于唯一的情况,我std::unique_ptr<T[]>当一个std::unique_ptr<T[]>有意义的时候,当你使用一个类C的API,返回一个原始指针到你认为拥有的堆数组。

我认为Charles Salvia的答案是相关的: std::unique_ptr<T[]>是初始化一个空数组的大小在编译时不知道的唯一方法。 Scott Meyers对使用std::unique_ptr<T[]>动机有什么看法?

一些常见的模式可以在一些 Windows的Win32 API调用中find,其中使用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, eg // // 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::vectorstd::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()); } 

我已经使用unique_ptr<char[]>来实现在游戏引擎中使用的预先分配的内存池。 这个想法是提供预分配的内存池,而不是dynamic分配用于返回碰撞请求结果和其他像粒子物理的东西,而不必在每一帧分配/释放内存。 对于这种需要内存池来分配有限生命周期(通常为一帧,两帧或三帧)的对象的情况,这种方式非常方便,不需要销毁逻辑(只有内存释放)。

简而言之:它是迄今为止最有效的内存。

一个std::string带有一个指针,一个长度和一个“短string优化”缓冲区。 但是我的情况是我需要存储一个几乎总是空的string,这个string我有成千上万的结构。 在C中,我只是使用char * ,大部分时间它将是空的。 这也适用于C ++,除了char *没有析构函数,并且不知道要删除它自己。 相比之下, std::unique_ptr<char[]>在超出作用域时会自行删除。 一个空的std::string占用了32个字节,但是一个空的std::unique_ptr<char[]>占用了8个字节,也就是它的指针大小。

最大的缺点是,每次我想知道string的长度,我必须调用strlen

它们可能是最可能的答案,当你只能通过一个现有的API(思考窗口消息或线程相关的callback参数)捅一个单一的指针,在孵化的另一边有一定的生命期后,但是与调用代码无关:

 unique_ptr<byte[]> data = get_some_data(); threadpool->post_work([](void* param) { do_a_thing(unique_ptr<byte[]>((byte*)param)); }, data.release()); 

我们都希望事情对我们很好。 C ++是其他时间。

  • 你需要你的结构只包含一个二进制兼容性原因的指针。
  • 您需要与返回分配有new[]内存的API进行交互
  • 例如,您的公司或项目有一个通用的规则来防止使用std::vector ,以防止不小心的程序员无意中引入副本
  • 你想防止不小心的程序员在这种情况下意外地引入副本。

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

可以使用unique_ptr<char[]>来表示C的性能和C ++的便利性。 考虑你需要在数百万(好吧,如果你不信任的话,数十亿)的string操作。 将它们中的每一个存储在单独的stringvector<char>对象中将是内存(堆)pipe理例程的灾难。 特别是如果你需要多次分配和删除不同的string。

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

通过类推,相同的性能和便利性考虑适用于非char数据(考虑数百万个向量/matrix/对象)。

我遇到了一个情况,我不得不使用std::unique_ptr<bool[]> ,这是在HDF5库(高效的二进制数据存储库,在科学中使用了很多库)。 一些编译器(在我的情况下是Visual Studio 2015) 提供了对std::vector<bool>压缩 (通过在每个字节中使用8个std::vector<bool> ),这对HDF5这样的事情来说是一场灾难,它不关心压缩。 用std::vector<bool> ,HDF5最终因为压缩而读垃圾。

猜猜是谁在救援,在std::vector无法正常工作的情况下,我需要干净地分配一个dynamic数组? 🙂

如果你需要一个不能复制的dynamic数组对象,那么一个智能指针指向数组是一个很好的select。 例如,如果你需要一个primefacesarrays。