Having a weak_ptr vector, you want to return the shared_ptr vector

I am currently working on a large project and I need to use weak_ptr instead of shared_ptr .

Here is my problem.

I have a class called House with the attribute: vector<boost::shared_ptr<People>> my_people . I want to change this data item as vector<boost::weak_ptr<People>> my_people .

My recipient was

 vector<boost::shared_ptr<People>>& getPeople() const { return my_people; } 

Usually with simple weak_ptr I can return my_people.lock();

But I have a vector, and I do not know how to do this:

 vector<boost::shared_ptr<People>>& getPeople() const { for( vector<boost::weak_ptr<People>::iterator it = my_people.begin(); it != my_people.end(); ++it) { (*it).lock(); } return my_people; } 

In other words, I want to return my weak_ptr vector, but as a shared_ptr vector. Is it possible? Or do I need to return the weak_ptr vector and use lock() wherever I use them?

+6
source share
4 answers

Your function is a smart start:

 vector<boost::shared_ptr<People>>& getPeople() const { for( vector<boost::weak_ptr<People>::iterator it = my_people.begin(); it != my_people.end(); ++it) { (*it).lock(); } return my_people; } 

But calling (*it).lock() just creates shared_ptr and discards it, it does not change the type of vector elements, and you cannot return the vector as another type.

You need to create a vector of the desired type, fill it with shared_ptr objects and return it:

 vector<boost::shared_ptr<People>> getPeople() const { vector<boost::shared_ptr<People>> people(my_people.size()); std::transform(my_people.begin(), my_people.end(), people.begin(), boost::bind(&boost::weak_ptr<People>::lock, _1)); return people; } 

This my_people over each element of my_people , calls lock() on it, and assigns the result to the corresponding element people .

If you know that my_people never contains obsolete pointers, this is even simpler:

 vector<boost::shared_ptr<People>> getPeople() const { vector<boost::shared_ptr<People>> people(my_people.begin(), my_people.end()); return people; } 

This populates the people vector, creating each shared_ptr element from the weak_ptr element. The difference is that this version will throw an exception if weak_ptr expired, because the shared_ptr constructor throws if weak_ptr has expired. The version using transform will put the empty vector shared_ptr into the vector if the expired weak_ptr is converted.

+2
source

What about:

 vector<boost::shared_ptr<People>> getPeople() const { vector<boost::shared_ptr<People>> res; for( vector<boost::weak_ptr<People>::iterator it = my_people.begin(); it != my_people.end(); ++it) res.push_back(it->lock()); return res; } 

In addition, you can filter null pointers if you wish.

Of course, you cannot return a link to a local variable, so you need to return a copy. Instead, you can:

 void getPeople(vector<boost::shared_ptr<People>> &res) const { for( vector<boost::weak_ptr<People>::iterator it = my_people.begin(); it != my_people.end(); ++it) res.push_back(it->lock()); } 

to avoid copying the returned vector.

+1
source

Note that vector<weak_ptr<T> > and vector<shared_ptr<T> > are two completely different types.

However, you can write a function that takes the first and returns the last:

  template<class Ptrs, class WeakPtrs> void lockWeakPtrs(const WeakPtrs &weakPtrs, Ptrs &ptrs) { BOOST_FOREACH (typename WeakPtrs::const_reference weakPtr, weakPtrs) { typename Ptrs::value_type ptr = weakPtr.lock(); if (ptr) // if you want to drop expired weak_ptr's ptrs.insert(ptrs.end(), ptr); } } 

Call: lockWeakPtrs(myWeakVector, mySharedVector);

0
source

You can use std :: transform

  std::vector<std::shared_ptr<People>> temp; sharedTargetList.resize(my_people.size()); //transform into a shared_ptr vector std::transform(my_people.begin(), my_people.end(), temp.begin(), [](std::weak_ptr<People> weakPtr){ return weakPtr.lock(); } ); 
0
source

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


All Articles