В настоящее время я работаю над большим проектом, и мне нужно использовать weak_ptr
вместо shared_ptr
,
Здесь моя проблема.
У меня есть класс с именем House с атрибутом: vector<boost::shared_ptr<People>> my_people
,
Я хочу изменить этот элемент данных, чтобы vector<boost::weak_ptr<People>> my_people
,
Мой добытчик был
vector<boost::shared_ptr<People>>& getPeople() const
{
return my_people;
}
Как правило, с простым weak_ptr
Я могу вернуться my_people.lock();
Но у меня есть вектор, и я не знаю, как сделать что-то вроде этого:
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;
}
Другими словами, я хочу вернуть мой вектор weak_ptr
но как вектор shared_ptr
, Является ли это возможным? Или я должен вернуть вектор weak_ptr
и использовать lock()
везде я их использую?
Ваша функция — разумное начало:
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;
}
Но зовет (*it).lock()
просто создает shared_ptr
и выбрасывает его, он не меняет тип векторных элементов, и вы не можете вернуть вектор как другой тип.
Вам нужно создать вектор правильного типа, заполнить его объектами shared_ptr и вернуть его:
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;
}
Это перебирает каждый элемент my_people
, звонки lock()
и присваивает результат соответствующему элементу people
,
Если вы знаете, что my_people
никогда не содержит просроченных указателей, это даже проще:
vector<boost::shared_ptr<People>> getPeople() const
{
vector<boost::shared_ptr<People>> people(my_people.begin(), my_people.end());
return people;
}
Это заполняет people
вектор путем построения каждого shared_ptr
элемент из weak_ptr
элемент. Разница в том, что эта версия будет выдавать исключение, если weak_ptr
истек, потому что shared_ptr
конструктор выбрасывает, если истек срок действия weak_ptr
, Версия, использующаяtransform
пустую shared_ptr
в векторе, если истек срок действия слабого_птр.
Как насчет:
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;
}
Кроме того, вы можете отфильтровать нулевые указатели, если хотите.
Конечно, вы не можете вернуть ссылку на локальную переменную, поэтому вы должны вернуть копию. Вы можете сделать вместо этого:
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());
}
чтобы избежать копирования обратного вектора.
Обратите внимание, что vector<weak_ptr<T> >
а также vector<shared_ptr<T> >
два совершенно разных типа.
Однако вы можете написать функцию, которая принимает первое и возвращает второе:
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);
}
}
Звоните так:
lockWeakPtrs(myWeakVector, mySharedVector);
Вы могли бы использовать станд :: преобразование
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(); }
);