std::end for unique_ptr<T[]>

std::end for unique_ptr<T[]>

本文关键字:gt lt ptr end for unique std      更新时间:2023-10-16

我想实现std::end唯一的指针。问题是我必须得到N(数组中元素的计数)

1。从模板

推断类型的方法
template <typename T, size_t N>
T* end(const unique_ptr<T[N]> &arr)
{
    return arr.get() + N;
}

但是我得到了错误错误:C2893:无法特化函数模板'T *test::end(const std::unique_ptr> &)' with [_Ty=T [N]]使用以下模板参数:'T=int' 'N=0x00'

看起来不可能推导出N

2。从分配器中获取N。分配器必须知道N才能正确执行delete[]。你可以在这篇文章中读到这一点。有两种方法:

  1. 过度分配数组,把n放在左边

  2. 使用以p为键,n为值的关联数组

问题是如何得到这个大小跨平台/编译器

也许有人知道更好的方法或知道如何使它工作?

如果你有一个运行时大小的数组,你需要知道它的大小,而不必手动做簿记,那么你应该使用std::vector。它将为您管理内存和大小。

std::unique_ptr<T[]>只是一个原始指针的包装器。您无法仅从指针获取指针所指向的块的大小。您使用std::unique_ptr<T[]>而不是T* foo = new T[size]的原因是unique_ptr确保在指针超出作用域时调用delete[]

像这样?

template<class X>
struct sized_unique_buffer;
template<class T, std::size_t N>
struct sized_unique_buffer<T[N]>:
  std::unique_ptr<T[]>
{
  using std::unique_ptr<T[]>::unique_ptr;
  T* begin() const { return this->get(); }
  T* end() const { return *this?begin(*this)+N:nullptr; }
  bool empty() const { return N==0 || !*this; }
};

,其中我们有一个编译时非强制的固定编译时长度的承诺。

类似的设计可以用于动态运行时长度。

在某些编译器中,当T可以被简单地销毁时,T的数目不会在调用new T[N]时被存储。系统可以自由地过度分配并为您提供更大的缓冲区(例如,对于大分配,将其四舍五入到页面边界,或者通过分配缓冲区的位置隐式存储缓冲区的大小,以减少开销并将分配四舍五入),因此分配大小不必完全匹配元素的数量。

对于非平凡销毁的T,编译器确实必须知道从指针中销毁多少。此信息不暴露给c++。

您可以手动分配缓冲区和计数,并将其传递给带有自定义删除器(甚至是无状态删除器)的unique_ptr。这将允许类型

unique_buffer<T[]> ptr;

,您可以以较低的运行时成本获得元素的数量。

如果您将长度存储在deleter中,您可以在循环限制上获得更多的局域性(节省缓存丢失),但代价是更大的unique_buffer<T[]>

使用未掺假的unique_ptr<T[]>以可移植的方式执行此操作是不可能的。