5

I came across something like:

using arr_t=std::array<std::array<std::array<int,1000>,1000>,1000>;
std::unique_ptr<arr_t> u_ptr;

The unique pointer was used, obviously, to overcome stackoverflow problem. Is there any case to use the previous code rather than just using std::vector ? Is there a real use case for std::unique_ptr<std::array<T,N>> ?

W.F.
  • 13,888
  • 2
  • 34
  • 81
Humam Helfawi
  • 19,566
  • 15
  • 85
  • 160
  • 3
    You can be sure that `arr_t` will never resize. Optimizations might find that useful. – Hatted Rooster May 03 '17 at 13:06
  • Very much related, possibly dupe: https://stackoverflow.com/questions/19111028/stddynarray-vs-stdvector – nwp May 03 '17 at 13:06
  • 2
    `std::vector` is not guaranteed to allocate the exact amount of space needed - it might allocate more. `std::array` has a fixed size. – Simon Kraemer May 03 '17 at 13:10
  • 3
    `arr_t` will allocate continuous memory block, `std::vector>>` will allocate memory in chunks `1000 * sizeof(int)` each. It could be important. – Michael Nastenko May 03 '17 at 13:16

1 Answers1

8

The code above generates one contiguous buffer of a billion elements, with [] access that lets you get at elements as a 3-dimensional 1000-sided cube.

A vector of vectors of vectors would be a whole pile of non-contiguous buffers linked by pointers and ownership semantics.

I suspect you are suggesting

using u_ptr=std::vector<std::array<std::array<int,1000>,1000>>;

then resizing said arr_t to 1000 once created. This has the modest cost of an extra 2 pointer overhead in the handle object. It also permits varible size, which means that ensuring it is fixed size as intended is something the user code has to ensure. You'd want to block a pile of methods, basically everything unique_ptr doesn't expose, to ensure safety, or audit that your code doesn't use any of them.

Some of those operations could be very expensive; .push_back({}) would reallocate a gigabyte.

Now, maybe you intend you won't ever call that; but if you have generic code that processes vectors, you'd have to audit all of it to ensure that none of it every does these operations. It isn't possible to have a non-const handle to a vector that cannot resize it, for example, without rolling-your-own-span-class at this point.

We could block the methods we do not want to expose with private inheritance and using statements, but at this point we end up doing most of the work to get back to the unique_ptr solution.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • Well, you can have a thin class that *contains* a private `std::vector`, and forwards all the relevant methods - you could even make it templated on the size, like `std::array`. And it wouldn't be too hard to audit it, if you did it properly. *Inheriting* from `std::array` is certainly a Bad Idea, agreed. – Toby Speight May 03 '17 at 13:40
  • @TobySpeight No, I mean inherit privately from `std::vector`, then `using vector::operator[]` and `using vector::size` the interfaces you want to re-export. Private inheritance involves far less boilerplate (and chances for typos) than has-a when you are just trying to reexport some parts of another class's interface. – Yakk - Adam Nevraumont May 03 '17 at 14:31
  • I hadn't considered private inheritance, but that makes sense. I was misdirected by talk of "blocking" methods, rather than of choosing which methods to publish. – Toby Speight May 03 '17 at 14:33