Converting a shared_ptr vector to a shared_ptr vector into const

Let

class A { std::vector<std::shared_ptr<int>> v_; }; 

Now I would like to add access to v_ using two public member functions

 std::vector<std::shared_ptr<int>> const & v() { return v_; } 

and

 std::vector<std::shared_ptr<int const> const & v() const { TODO } 

I can not replace TODO with return v_; .

One option is not to return the link, but copy. Besides the obvious performance degradation, this will also make the interface less desirable.

Another option is to make TODO equal to return reinterpret_cast<std::vector<std::shared_ptr<int const>> const &>(v_);

My question is: is this behavior undefined? Or, alternatively, is there a better option, preferably without using reinterpret_cast ?

+7
c ++ undefined-behavior vector reinterpret-cast
source share
2 answers

A way to avoid copying the container is to provide conversion iterators that transform the element when dereferencing:

 #include <vector> #include <memory> #include <boost/iterator/transform_iterator.hpp> class A { std::vector<std::shared_ptr<int> > v_; struct Transform { template<class T> std::shared_ptr<T const> operator()(std::shared_ptr<T> const& p) const { return p; } }; public: A() : v_{std::make_shared<int>(1), std::make_shared<int>(2)} {} using Iterator = boost::transform_iterator<Transform, std::vector<std::shared_ptr<int> >::const_iterator>; Iterator begin() const { return Iterator{v_.begin()}; } Iterator end() const { return Iterator{v_.end()}; } }; int main() { A a; // Range access. for(auto const& x : a) std::cout << *x << '\n'; // Indexed access. auto iterator_to_second_element = a.begin() + 1; std::cout << **iterator_to_second_element << '\n'; } 
+6
source share

Putting aside the discussion of whether to return a link to a member ...

std::vector already extends its own const qualifier to the links, pointers, and iterators it returns. The only obstacle is that it propagates further to the type pointee std::shared_ptr . You can use a class like std::experimental::propagate_const (which we hope will be standardized) to facilitate this. He will do, as his name implies, for any pointer or pointer object that he wraps.

 class A { using ptr_type = std::experimental::propagate_const<std::shared_ptr<int>>; std::vector<ptr_type> v_; }; 

So TODO can become return v_; , and any access to pointers (for example, based on the range that you want to maintain) will remain constant.

The only caveat is that it is only a movable type, so copying a vector element will require a bit more work (for example, calling std::experimental::get_underlying ) with the element type of the vector itself.

+3
source share

All Articles