Passing a vector unique_ptr to an object. the vector becomes a member variable. the right approach?

One object, which I will call "Owner", has clear ownership of a vector of data objects during its lifetime.

They are stored as a unique_ptr vector.

One object / class called "Output" has to look at these data objects in different ways and therefore some type of reference / pointer / variable is a member variable "Output".

The inference takes a vector of data objects in its constructor.

I thought of three ways to achieve this. What will be considered the best way?

Option 1 - the "output" object stores the vec data as a const reference:

class Output {
    // output wants the data:
 public:
    Output(std::vector<std::unique_ptr<Data>> const & in)
        : my_lot_of_data(in) {
    };
    std::vector<std::unique_ptr<Data>> const & my_lot_of_data;
}

      

which is created by "Owner" with:

 data_vec_.push_back(std::unique_ptr<Data>(new Data));
 /* stuff happens to data */
 Output output(data_vec_);

      

Option 2 - the "output" object stores the vec data as a const pointer:

class Output {
    // output wants the data:
 public:
    Output(std::vector<std::unique_ptr<Data>> const * in)
        : my_lot_of_data(in) {
    };
    std::vector<std::unique_ptr<Data>> const * my_lot_of_data;
}

      

which is created by "Owner" with:

 data_vec_.push_back(std::unique_ptr<Data>(new Data));
 /* stuff happens to data */
 Output output(&data_vec_);

      

Option 3 - the "output" object receives raw pointers:

class Output {
    // output wants the data:
 public:
    Output(std::vector<Data*> in)
        : my_lot_of_data(in) {
    };
    std::vector<Data*> const my_lot_of_data;
};

      

which is created by "Owner" with:

 data_vec_.push_back(std::unique_ptr<Data>(new Data));
 /* stuff happens to data */
 std::vector<Data*> data_as_raw;
 data_as_raw.resize(data_vec_.size());
 std::transform(data_vec_.begin(), data_vec_.end(), data_as_raw.begin(), [](std::unique_ptr<Data> const & x) {return x.get();});
 Output output(data_as_raw);

      

Additional queries: In options 1 and 2, it is clear that Output has no ownership of the data, even though it is stored as unique_ptrs? Could Option 3 get confused on the calling site? It takes 3 more lines to achieve the same result.

What's the best thing here?

+3


source to share


4 answers


Since you are using unique_ptr, you are not going to share this data with anything that might take longer than the Owner, so a simple constant reference should be fine. I would recommend a good typedef:

typedef std::vector<std::unique_ptr<Data>> OwnerDataSet;
Output(const OwnerDataSet &in)

      

The advantage of Approach 1 is that it is simple and straightforward. Others just complicate it for no apparent reason.

The unique_ptr function is to remove new data when std :: vector is destroyed. The alternative here would be to copy the Data instance instead of calling new. If you don't need to work with pointers, you don't need special handling like unique_ptr to keep them safe.



typedef std::vector<Data> OwnerDataSet;
OwnerDataSet results;
Data match = findoneresult();
results.push_back(match); // copy something from Owner
Output (results);

      

And to take it one step further, it is not clear from your examples why you support std :: vector outside of the Output class. Since you are calling std :: unique_ptr (new T) on everything passed in, I suspect you are only using it with Output, so you can do this:

class Output : public std::vector<Data> {
    void PrintToScreen();
    void WriteToDatabase();
    void OrWhatever();
};

Output x;
Data match = findoneresult();
x.push_back(findoneresult());
x.PrintToScreen();

      

+2


source


If you only want to "read some of the values ​​and then [create] various output files", I'll just make it a function that takes const-ref:

void output(std::vector<std::unique_ptr<Data>> const& data) {
    // stuff
}

      



I prefer const&

- const*

for the semantics of use ( data[0]

vs (*data)[0]

) and definitely prefer how to pass raw data - don't give up your explicit ownership of anything (and that's not even for convenience, given that this is annoying to the construct anyway vector<Data*>

)

+2


source


I would mix the first two approaches: let the Output constructor take a const-ref vector, but store it as a const pointer. This is because const pointers can be copied, so the entire output object can be assigned if needed.

0


source


If possible, I would avoid skipping the vector altogether and have the unique_ptr vector encapsulated inside Owner

. Can I Output

have a pointer / reference to Owner

and receive raw pointers to individual elements Data

from Owner

?

class Owner {
  private:
    std::vector<std::unique_ptr<Data>> data_vec_;
  public:
    const Data* getData(size_t i) const { return data_vec_.at(i).get(); }
    size_t getSize() const { return data_vec_.size(); }
};

class Output {
  private:
    const Owner& owner_;   
  public:
    Output(const Owner& owner) : owner_(owner) { }
    void doSomething() { 
         // get some data
         auto data = owner_.getData(0);

         // use data...
    }
};

      

0


source







All Articles