Temporary Permanent Permanent Copy of unique_ptr

I am new to C ++ 11 smart pointers and I am trying to use them effectively in a project. In my project, I have many functions that take a constant reference to vector of unique_ptr , perform some calculations on it and put some results in the returned parameter, for example:

 void computeCoefficients(const vector<unique_ptr<Scalar>>& roots, vector<unique_ptr<Scalar>>& coeffs) { ... } 

I use unique_ptr because the procedure that calls all of these functions is the sole owner of the objects in vector , and the functions simply “borrow” the objects to read them as input.

Now I'm trying to write a function that performs calculations on the different subsets of vector that it receives, and for this it needs to have different "versions" of vector containing these subsets, in order to go to another function that accepts the input vector<unique_ptr<Scalar>> . But the only way to get a subset of a vector is to make a copy of it - which is a problem because unique_ptr cannot be copied. I would like the code to look something like this:

 void computeOnSet(const vector<unique_ptr<Scalar>>& set, unique_ptr<Scalar>& output) { ... } void computeOnAllSubsets(const vector<unique_ptr<Scalar>>& set, vector<unique_ptr<Scalar>>& outputs) { for(int i = 0; i < input.size(); i++) { auto subset = vector<unique_ptr<Scalar>>(set.begin(), set.begin()+i); subset.insert(subset.end(), set.begin()+i+1, set.end(); computeOnSubset(subset, outputs.at(i)); } } 

Of course, this does not work. I could make it work if I replaced unique_ptr with shared_ptr s, but it has two problems:

  • It would philosophically mean that I share the ownership of the set using the computeOnSubsets function, and I do not; the caller remains the sole owner. (I read that shared_ptr means that you share the property with everything that has a copy of it).
  • This will lead to overhead for link counting even in places where I don’t need it, because it will force me to change the input parameter of all my methods to vector<shared_ptr<Scalar>> .

All I want to do is make a temporary copy of the read-only pointer for the sole purpose of creating temporary read-only sub-vectors. Is there any way to do this? weak_ptr sounds like what I need (not owning a temporary pointer), but it can only be used with shared_ptr .

+8
c ++ c ++ 11 stdvector unique-ptr shared-ptr
source share
2 answers

I use unique_ptr because the procedure that calls all of these functions is the sole owner of the objects in the vector, and the functions simply “borrow” the objects to read them as input.

Since computational functions do not own the indicated objects, just observing their state and computing, you should pass them a vector of observing pointers (in this case, regular raw pointers ) instead of the unique_ptr s vector.

Since computeOnAllSubsets() and computeOnSet() not responsible for the lifetime of Scalar objects, they should not even acquire their property - in other words, they should not receive owners of unique_ptr s.

In the end, the logic of your program is guaranteed that these functions will not get dangling links, because your own function will not destroy its vector before it performs all the necessary calculations. This is directly supported by what you write:

All I want to do is make a temporary copy of the read-only pointer for the sole purpose of creating temporary read-only sub-vectors. Is there any way to do this?

Just pass the vector of source pointers to your computational functions . Given unique_ptr , you can access the encapsulated raw pointer by calling the get() member function:

 std::unique_ptr<Scalar> pS // ... initialized somehow Scalar* pScalar = pS.get(); 

As an alternative to the source pointers, you can use std::reference_wrapper to send watch links. Especially during the refactoring process of an outdated code base, where source pointers are used for manual memory management, this makes it clear that ownership of the objects referenced belongs elsewhere.

Note, however, that in Modern C ++, raw pointer is most often synonymous with watch pointers, so the above difference does not make much sense in a generalized context. A use case for which std::reference_wrapper is fundamental is when you want to pass objects by reference to some function template that takes its arguments by value ( std::bind() is a typical example).

+9
source share

Using an iterator can make your code more versatile. Just declare your computational function as follows:

 template <typename InputIt, typename OutputIt> void compute(InputIt first_it, InputIt last_it, OutputIt d_first, Output d_last); 

This calculation function template processes data in the range [first_it, last_it) and then puts the result in [d_first, d_last) . He does not care about the type of input or output containers. Iterators act as pointers to elements in the container, which is the idea of ​​STL.

In addition, in some cases, you do not even go through the range manually. Just use function templates in <algorithm> , for example std::for_each and std::transform .

I really don't understand the code snippet in computeOnAllSubsets , but instinctively I think std::transform might be useful.

+2
source share

All Articles