Effective conversion between vector <shared_ptr <T>> and vector <shared_ptr <const T >>
I have a class:
class X { vector<shared_ptr<T>> v_; public: vector<shared_ptr<const T>> getTs() { return v_; } }; It has a vector of shared_ptr type T For some reason, he needs to set a method to return this vector. However, I do not want the contents of the vector to be changed and objects not to be specified. So I need to return vector from shared_ptr<const T> .
My question is, is there an effective way to achieve this? If I just return it, it works, but it needs to restore a vector, which is quite expensive.
Thanks.
You cannot do this directly - but you can define “views” in your container that will allow you to do something very similar if you want to make sure your pointers are const:
boost::any_range< std::shared_ptr<const int>, boost::random_access_traversal_tag, std::shared_ptr<const int>, std::ptrdiff_t > foo(std::vector<std::shared_ptr<int>>& v) { return v; } A simple iterator-adapter / transformed range conversion can also do the trick, I just used this to illustrate this point.
Why not return it as a set of iterator s?
class X { vector<shared_ptr<T>> v_; class const_iterator : std::iterator< std::bidirectional_iterator_tag, T > { vector<shared_ptr<T>>::iterator it; const_iterator( vector<shared_ptr<T>>::iterator& v ) :it (v) { } const T& operator*() { return const_cast<const T>( **it ); } //forward all methods } public: const_iterator ts_begin() { return const_iterator(v_.begin()); } const_iterator ts_end() { return const_iterator(v_.end()); } }; or something similar? This gives you full control over the type and access to it. In addition, you can change the type later without changing the api.
You return by value, so the cost will be the same if you return a copy of the original, vector, or a copy of the shared_ptr<T const> vector: one memory allocation and N atomic increments (approximately).
If you need to avoid creating a return vector (i.e., returning by value), then this is not possible, since different instances of templates are unrelated types no matter how arguments are related to the template.
A typical solution is to return a const reference:
class X { vector<shared_ptr<T>> v_; public: const vector<shared_ptr<T>>& getTs() const { return v_; } }; With this return type, vector<shared_ptr<T>>& other objects cannot change your inner vector.
BUT , however, this violates encapsulation. Your v_ is no longer a private part of X - it is only private to write the aspect.
Real encapsulation is as follows:
class X { vector<shared_ptr<T>> v_; public: class const_ts_iterator { public: //define all necessary stuff private: vector<shared_ptr<T>>::const_iterator it; }; size_t getTsSize() const { return v_.size; } const T* getTsAt(size_t i) const { return v_.at(i).get(); } const_ts_iterator beginTs() const { return v_.cbegin(); } const_ts_iterator endTs() const { return v_.cend(); } };