C++ 使用阵列是否有任何独特的_ptr用途?
C++ 使用阵列是否有任何独特的_ptr用途?,c++,c++11,smart-pointers,unique-ptr,C++,C++11,Smart Pointers,Unique Ptr,std::unique_ptr支持阵列,例如: std::unique_ptr<int[]> p(new int[10]); std::unique_ptr p(新整数[10]); 但这是必要的吗?使用std::vector或std::array可能更方便 你觉得这个构造有用吗?可以复制std::vector,而unique\u ptr可以表示数组的唯一所有权std::array要求在编译时确定大小,这在某些情况下可能是不可能的。有些人甚至使用分配器也没有使用std::vecto
std::unique_ptr
支持阵列,例如:
std::unique_ptr<int[]> p(new int[10]);
std::unique_ptr p(新整数[10]);
但这是必要的吗?使用std::vector
或std::array
可能更方便
你觉得这个构造有用吗?可以复制
std::vector
,而unique\u ptr
可以表示数组的唯一所有权<另一方面,code>std::array要求在编译时确定大小,这在某些情况下可能是不可能的。有些人甚至使用分配器也没有使用std::vector
的奢侈。有些人需要一个动态大小的数组,所以std::array
已经过时了。有些人从其他已知返回数组的代码中获取数组;代码不会被重写为返回一个向量
通过允许unique\u ptr
,您可以满足这些需求
简言之,您可以在需要时使用unique\ptr
。当替代方案根本不适合你的时候。这是一个万不得已的工具。我使用了unique\u ptr
来实现游戏引擎中使用的预分配内存池。其思想是提供预先分配的内存池,而不是动态分配,用于返回碰撞请求结果和其他内容,如粒子物理,而无需在每个帧分配/释放内存。对于这种需要内存池来分配生命周期有限(通常为1、2或3帧)且不需要销毁逻辑(仅内存释放)的对象的场景,这非常方便 存在权衡,您可以选择符合您需要的解决方案。不经意间:
初始尺寸
vector
和unique\ptr
允许在运行时指定大小
array
仅允许在编译时指定大小
调整大小
array
和unique\ptr
不允许调整大小
vector
储藏
vector
和unique\ptr
将数据存储在对象外部(通常在堆上)
array
将数据直接存储在对象中
临摹
数组
和向量
允许复制
唯一\u ptr
不允许复制
交换/移动
vector
和unique_ptr
具有O(1)时间交换和移动操作
array
有O(n)个timeswap
和move操作,其中n是数组中的元素数
指针/引用/迭代器无效
array
确保指针、引用和迭代器在对象处于活动状态时永远不会失效,即使在swap()
unique\u ptr
没有迭代器;指针和引用仅在对象处于活动状态时通过swap()
无效。(交换后,指针指向您交换的数组,因此在这个意义上它们仍然是“有效的”。)
vector
可能会使任何重新分配上的指针、引用和迭代器无效(并提供某些保证,即重新分配只能发生在某些操作上)
与概念和算法的兼容性
array
和vector
都是容器
唯一\u ptr
不是容器
我必须承认,这似乎是一个利用基于策略的设计进行重构的机会。当您只需在现有API(想想窗口消息或线程相关回调参数)中插入一个指针时,它们可能是最正确的答案,这些API在被“捕获”后具有一定的生命周期在图案填充的另一侧,但与调用代码无关:
unique_ptr<byte[]> data = get_some_data();
threadpool->post_work([](void* param) { do_a_thing(unique_ptr<byte[]>((byte*)param)); },
data.release());
unique_ptr data=get_some_data();
threadpool->post_work([](void*param){do_a_thing(unique_ptr((byte*)param));},
data.release());
我们都希望事情对我们有利。C++是其他时候。< p> >如果你不想支付数组的运行时成本,你可以使用<代码> UnQuyGPPT。
std::vector<char> vec(1000000); // allocates AND value-initializes 1000000 chars
std::unique_ptr<char[]> p(new char[1000000]); // allocates storage for 1000000 chars
标准向量向量向量(1000000);//分配并初始化1000000个字符
std::unique_ptr p(新字符[1000000]);//为1000000个字符分配存储
std::vector
构造函数和std::vector::resize()
将值初始化T
——但是如果T
是POD,则new
不会这样做
看
请注意,vector::reserve
不是此处的替代方案:
这与C程序员可能选择
malloc
而不是calloc的原因是一样的,在WindowsWin32 API调用中可以找到一种常见的模式,在这种模式中,使用std::unique_ptr
很方便,例如,在调用某些Win32 API时,您不知道输出缓冲区应该有多大(这将在该缓冲区内写入一些数据):
//由调用方动态分配的缓冲区,并由某些Win32 API函数填充。
//(将在下面的“while”循环中进行分配。)
std::唯一的ptr缓冲区;
//缓冲区长度,以字节为单位。
//使用期望在第一次API调用时成功的初始长度进行初始化。
UINT32缓冲区长度=/*…*/;
LONG returnCode=错误\u缓冲区不足\u;
while(returnCode==错误\u缓冲区不足)
{
//分配指定长度的缓冲区
复位(字节[bufferLength]);
//
//或者,在C++14中,可以使用make_unique()代替,例如。
//
//buffer=std::使_唯一(bufferLength);
//
//
//调用一些Win32 API。
//
//如果缓冲区的大小(存储在“bufferLength”中)不是
// 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...
...
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());
}
class ALargeAndComplicatedClassWithLotsOfDependencies;
class MyClass {
...
private:
std::unique_ptr<ALargeAndComplicatedClassWithLotsOfDependencies[]> m_InternalArray;
};
#include "myclass.h"
#include "ALargeAndComplicatedClassWithLotsOfDependencies.h"
// MyClass implementation goes here
Dynamic | Runtime static | Static
Stack std::vector unique_ptr<T[]> std::array
Heap std::vector unique_ptr<T[]> unique_ptr<std::array>