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.

+4
source share
4 answers

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.

+4
source

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.

+2
source

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.

+1
source

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(); } }; 
0
source

Source: https://habr.com/ru/post/1439922/


All Articles