2012-10-15 10 views
6

Attualmente sto lavorando su un grande progetto e ho bisogno di usare weak_ptr invece di shared_ptr.Avendo un vettore di weak_ptr, voglio restituire un vettore di shared_ptr

Ecco il mio problema.

Ho una classe denominata Casa con un attributo: vector<boost::shared_ptr<People>> my_people. Desidero modificare questo membro dati per essere vector<boost::weak_ptr<People>> my_people.

mio getter era

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

Normalmente, con un semplice weak_ptr posso tornare my_people.lock();

Ma ho un vettore e non so come fare qualcosa di simile:

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 altre parole, voglio restituire il mio vettore di weak_ptr ma come vettore di shared_ptr. È possibile? O devo restituire un vettore di weak_ptr e utilizzare lock() ovunque io li usi?

+0

Avete davvero bisogno di 'weak_ptr' in primo luogo? –

risposta

1

Che dire:

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

Inoltre, è possibile filtrare i puntatori nulli, se si vuole.

Ovviamente, non è possibile restituire un riferimento a una variabile locale, quindi è necessario restituire una copia. Si consiglia di fare invece:

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

per evitare di copiare il vettore di restituzione.

+0

Ci ho pensato ma, voglio fare operazioni sull'attributo my_people, non su una copia? – blackmesa

+0

@ user1747056 quindi devi scrivere una funzione che prenda un elemento vettoriale specifico, lo blocchi, lo modifichi. –

+1

Vuoi dire che il chiamante può modificare (aggiungere/eliminare) l'elenco? Se è così, temo che tu abbia bisogno di qualcosa di più complicato di così. Ad esempio, puoi avere un 'getPeople()' come nella mia risposta, e poi un 'setPeople (const vector > & ps)' che rimette l'elenco modificato sotto forma di un 'vector ' . Quindi puoi racchiudere le chiamate su 'getPeople/setPeople' usando il costruttore/distruttore di una classe helper. Ma direi che stai andando meglio con l'ovvio: cambia i chiamanti per usare 'weak_ptr'. O ancora meglio, non lasciare che il chiamante modifichi la lista! – rodrigo

0

Si noti che vector<weak_ptr<T> > e vector<shared_ptr<T> > sono due tipi completamente diversi.

Tuttavia, è possibile scrivere una funzione che accetta il primo e restituisce il secondo:

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

chiamata in questo modo: lockWeakPtrs(myWeakVector, mySharedVector);

2

vostra funzione è un inizio ragionevole:

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

Ma chiamare (*it).lock() crea appena un shared_ptr e lo getta via, non cambia il t ype degli elementi del vettore e non è possibile restituire il vettore come un tipo diverso.

È necessario creare un vettore del tipo giusto, riempirlo con gli oggetti shared_ptr, e restituirla:

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

Questo itera su ogni elemento della my_people, chiamate lock() su di esso, e assegna il risultato all'elemento corrispondente di people.

Se si sa che my_people mai contiene i puntatori scaduti è ancora più facile:

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

Questo riempie il people vettore con la costruzione di ogni elemento shared_ptr da un elemento weak_ptr. La differenza è che questa versione genererà un'eccezione se uno weak_ptr è scaduto perché il costruttore shared_ptr genera se è scaduto uno weak_ptr scaduto. La versione che utilizza transform inserirà un vuoto shared_ptr nel vettore se viene trasformato un weak_ptr scaduto.

0

Si potrebbe utilizzare 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(); } 
); 
Problemi correlati