0

I have a large codebase that uses std::vector as data storage for numbers. However, now I need to add support for raw data views, due to external C library that returns raw array. Due to performance reasons, I dont want to copy data to std::vector.

I was thinking to use std::span from C++20 and create my own storage class like this:

template <typename T>
class DataStorage {
private:
   std::vector<T> data;

public:

   std::span<T> view;

   DataStorage(const std::vector<T>& d) : 
      data(d),
      view(data) {
   }

   DataStorage(T* d) : 
      data(),
      view(d) {
   }


   //other ctors
   //and methods
}

std::vector<int> vect{ 10, 20, 30 };
DataStorage<int> data(vect);
int value = data.view[1];

To read from data, view will be used. If data are passed via vector, DataStorage clas will own them. If I pass data via raw pointer (or with some flag), DataStorage will create only view. Is this a valid design?

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Martin Perry
  • 9,232
  • 8
  • 46
  • 114
  • How exactly would you use this type? Like, what does it mean for a function to take an object of this type? What will the function do with it? "*Due to performance reasons, I dont want to copy data to std::vector.*" But you are copying it; it happens right there in one of the constructors of `DataStorage`. – Nicol Bolas Sep 18 '22 at 16:28
  • Also, if you copy/move the `DataStorage` that has a `vector`, the copy will be broken. The new `vector` stored internally will be fine, but the `span` will point at the old data. Which in the case of a move, has been destroyed. – Nicol Bolas Sep 18 '22 at 16:30
  • @NicolBolas One ctor copy data, but the other one only use `span` and `vector` itself is kept empty. If I copy/move class, I have to change `span` content according to the new storage in copy/move ctor (that will be added to class). – Martin Perry Sep 18 '22 at 17:05
  • 1
    @MartinPerry So now a user of the class can't tell whether the data is owned or not. Therefore they have to play it safe and use the class as if it was non-owning. But for that you could have simply used `std::span` to begin with. – user17732522 Sep 18 '22 at 17:11
  • @user17732522 If `vector` is empty, data are not owned. If `vector` is filled, data are owned. – Martin Perry Sep 18 '22 at 17:27
  • @MartinPerry: You're kind of missing the point. The code *receiving* such an object does not know what to do with it. If it is going to store that object long-term, then (outside of some agreement that non-owning spans will be preserved by the outside world) it *must* copy it when it does that storing. So... it may as well have done that to begin with. So what's the point of the object? – Nicol Bolas Sep 18 '22 at 17:31
  • @MartinPerry: I feel like this is an XY problem. That your real problem is something else which you feel has forced you into creating this type. – Nicol Bolas Sep 18 '22 at 17:31
  • 2
    @MartinPerry Suppose a function takes a `DataStorage` as argument and intents to store it into a class member for later use. It can't do this without branching on whether `std::span` or `std::vector` is active and copying the data in the first case. If the function does not intent to store the data beyond its execution, it doesn't need to take an owning type at all. `std::span` will do. Also as a side note, `std::variant` is probably a better choice than two members leaving one empty. – user17732522 Sep 18 '22 at 17:31

0 Answers0