std::end 用于 unique_ptr<T[]>。

3

我想为unique指针实现std::end。 问题是我需要获取N(数组中元素的数量)。

1.方法:从模板中推导类型

template <typename T, size_t N>
T* end(const unique_ptr<T[N]> &arr)
{
    return arr.get() + N;
}

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

看起来不可能推断出 N 的值。

2.从分配器中获取 N。 分配器必须知道 N 才能正确执行 delete[] 操作。您可以在 这篇文章 中了解更多信息。有两种方法:

  1. 过度分配数组,并将 n 置于其左侧。

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

问题在于如何跨平台/编译器获取此大小。

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


这段代码是能够正常工作的……如果你真的有一个unique_ptr<T[N]>可以传递给end,而不是一个unique_ptr<T[]>。在你的问题中,你或许还可以展示一些你打算如何调用end的相关代码。 - Aaron McDaid
2个回答

8
如果您有一个运行时大小的数组,并且需要知道其大小而不必手动进行簿记,则应使用std::vector。它将为您管理内存和大小。 std::unique_ptr<T[]>只是一个原始指针的包装器。您无法仅通过指针获取指针所指向的块的大小。之所以使用std::unique_ptr<T[]>而不是T* foo = new T[size]是因为unique_ptr确保在指针超出作用域时调用delete[]

0

像这样的东西?

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; }
};

在编译时,我们承诺有一个固定的编译时长度,但这个承诺并没有被强制执行。

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

在一些编译器中,当你调用new T[N]时,对于可以轻松销毁的T的数量并没有被存储。系统可以自由地进行超额分配并给你一个更大的缓冲区(例如,对于大型分配,将其舍入到页面边界,或通过从其分配位置隐式存储缓冲区的大小以减少开销并将分配舍入),因此分配大小不需要完全匹配元素数量。

对于非轻松销毁的T,编译器必须知道从指针中销毁多少个。这些信息在C++中没有暴露出来。

您可以手动分配缓冲区和计数,并将其传递给具有自定义删除器的unique_ptr,即使是无状态的unique_ptr。这将允许一种类型。

unique_buffer<T[]> ptr;

你可以在运行时间成本较低的情况下获取元素数量。

如果你将长度存储在删除器中,你可以在循环限制上获得更多的局部性(节省缓存未命中),但代价是需要一个更大的unique_buffer<T[]>

使用未经修改的unique_ptr<T[]>无法以可移植的方式实现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接