简体   繁体   中英

std::end for unique_ptr<T[]>

I want to implement std::end for unique pointer. The problem is that I have to get N(count of elements in array).

1.Approach deduce type from template

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

But I got error error: C2893: Failed to specialize function template 'T *test::end(const std::unique_ptr> &)' with [ _Ty=T [N] ] With the following template arguments: 'T=int' 'N=0x00'

It looks like It is not possible to deduce N

2.Get N from allocator. Allocator has to know N to correctly execute delete[]. You could read about this in this article . There are two approaches:

  1. Over-allocate the array and put n just to the left.

  2. Use an associative array with p as the key and n as the value.

The problem is how to get this size cross platform/compiler.

Maybe someone knows better approaches or know how to make this works?

If you have a run time sized array and you need to know the size of it without having to manually do the book keeping then you should use a std::vector . It will manage the memory and size for you.

std::unique_ptr<T[]> is just a wrapper for a raw pointer. You cannot get the size of the block the pointer points to from just the pointer. The reason you use a std::unique_ptr<T[]> over T* foo = new T[size] is the unique_ptr makes sure delete[] is called when the pointer goes out of scope.

Something like this?

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

where we have a compile-time unenforced promise of a fixed compile-time length.

A similar design could work for a dynamic runtime length.

In some compilers, the number of T when T can be trivially destroyed is not stored when you call new T[N] . The system is free to over-allocate and give you a larger buffer (ie, round to a page boundary for a large allocation, or implicitly store the size of the buffer via the location from which it is allocated to reduce overhead and round allocations up), so the allocation size need not exactly match the number of elements.

For non-trivially destroyed T it is true that the compiler must know how many to destroy from just the pointer. This information is not exposed to C++.

You can do manual allocation of buffers and the count and pass that on to a unique_ptr with a custom deleter, even a stateless one. This would permit a type

unique_buffer<T[]> ptr;

where you can get the number of elements out at only a modest runtime cost.

If you instead store the length in the deleter, you can get a bit more locality on the loop limits (saving a cache miss) at the cost of a larger unique_buffer<T[]> .

Doing this with an unadulterated unique_ptr<T[]> is not possible in a portable way.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM