2012-10-15 9 views
6

Obecnie pracuję nad dużym projektem i potrzebuję użyć weak_ptr zamiast shared_ptr.Posiadanie wektora weak_ptr, chcesz zwrócić wektor shared_ptr

Oto mój problem.

Mam klasę o nazwie Dom z atrybutem: vector<boost::shared_ptr<People>> my_people. Chcę zmodyfikować ten element danych na vector<boost::weak_ptr<People>> my_people.

Moja rodzicielka była

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

Normalnie, z prostym weak_ptr mogę wrócić my_people.lock();

Ale mam wektor i nie wiem, jak zrobić coś takiego:

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; 
} 

Innymi słowy, chcę zwrócić mój wektor weak_ptr, ale jako wektor shared_ptr. Czy to możliwe? Czy muszę zwrócić wektor weak_ptr i używać lock() wszędzie, gdzie ich używam?

+0

Czy naprawdę potrzebujemy 'weak_ptr' w pierwszej kolejności? –

Odpowiedz

1

Co o:

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; 
} 

Ponadto można odfiltrować NULL wskazówek, jeśli chcesz.

Oczywiście nie można zwrócić odniesienia do zmiennej lokalnej, więc musisz zwrócić kopię. Zamiast tego możesz wykonać następujące czynności:

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

, aby uniknąć kopiowania wektora powrotu.

+0

Myślałem o tym, ale chcę wykonywać operacje na atrybucie my_people, a nie na kopii? – blackmesa

+0

@ user1747056 to musisz napisać funkcję, która zajmie określony element wektorowy, zablokuj go, zmodyfikuj jego przedmiot. –

+1

Masz na myśli to, że dzwoniący może modyfikować (dodawać/usuwać) listę? Jeśli tak, obawiam się, że będziesz potrzebował czegoś bardziej skomplikowanego. Na przykład, możesz mieć 'getPeople()' jak w mojej odpowiedzi, a następnie 'setPeople (const vector > & ps)' który odkłada zmodyfikowaną listę w postaci 'wektora ' . Następnie możesz owijać wywołania 'getPeople/setPeople' używając konstruktora/destruktora klasy pomocnika. Ale powiedziałbym, że lepiej postępować z oczywistością: zmień rozmówców, aby użyli 'weak_ptr'. Lub jeszcze lepiej, nie pozwól, aby dzwoniący modyfikował listę! – rodrigo

0

Pamiętaj, że vector<weak_ptr<T> > i vector<shared_ptr<T> > to dwa zupełnie różne typy.

Można jednak napisać funkcję, która przyjmuje dawny i zwraca ostatni:

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); 
     } 
    } 

połączenia tak: lockWeakPtrs(myWeakVector, mySharedVector);

2

Twoja funkcja jest rozsądnym 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; 
} 

Ale wywołanie (*it).lock() po prostu tworzy shared_ptr i wyrzuca je, to nie zmienia t ype elementów wektorowych i nie można zwrócić wektora jako innego typu.

Musisz utworzyć wektor odpowiedni rodzaj, wypełnić go z obiektami shared_ptr i powrócić go:

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 iteracje nad każdym elementem my_people wzywa lock() na nim, i przypisuje wynik do odpowiedniego elementu people.

Jeśli wiesz, że nie zawiera my_people wygasłe wskaźniki jeszcze łatwiej:

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

ten wypełnia people wektora przez konstruowanie każdy element shared_ptr z elementu weak_ptr. Różnica polega na tym, że ta wersja wyrzuci wyjątek, jeśli wygasł weak_ptr, ponieważ konstruktor shared_ptr wyrzuca, jeśli minął wygasły weak_ptr. Wersja używająca transform wstawi pusty wektor shared_ptr, jeśli przeterminowana słaba_ptr zostanie przekształcona.

0

Można użyć 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(); } 
);