2011-11-23 14 views
20

Come si fa accesso unique_ptr elementi di un contenitore (tramite un iteratore) senza prendere possesso di distanza dal contenitore? Quando si ottiene un iteratore su un elemento nel contenitore, la proprietà dell'elemento è ancora presente nel contenitore? Che ne dici di quando si deruba l'iteratore per accedere a unique_ptr? Questo compie una mossa implicita di unique_ptr?l'iterazione di un contenitore di di unique_ptr

trovo sto usando shared_ptr molto quando ho bisogno di memorizzare gli elementi in un contenitore (non per valore), anche se il contenitore possiede concettualmente gli elementi e altro codice vuole semplicemente per manipolare gli elementi nel contenitore, perché io Ho paura di non essere in grado di accedere effettivamente agli elementi unique_ptr nel contenitore senza che ne sia stata presa la proprietà.

Eventuali approfondimenti?

risposta

13

Finché non si tenta di fare una copia del unique_ptr, si può semplicemente utilizzare. Dovrai "raddire la dereferenza" all'iteratore per ottenere il valore del puntatore, proprio come dovresti con shared_ptr. Ecco un breve esempio:

#include <vector> 
#include <memory> 
#include <iostream> 

template <class C> 
void 
display(const C& c) 
{ 
    std::cout << '{'; 
    if (!c.empty()) 
     std::cout << *c.front(); 
    for (auto i = std::next(c.begin()); i != c.end(); ++i) 
     std::cout << ", " << **i; 
    std::cout << "}\n"; 
} 

int main() 
{ 
    typedef std::unique_ptr<int> Ptr; 
    std::vector<Ptr> v; 
    for (int i = 1; i <= 5; ++i) 
     v.push_back(Ptr(new int(i))); 
    display(v); 
    for (auto i = v.begin(); i != v.end(); ++i) 
     **i += 2; 
    display(v); 
} 

Se lo fai (accidentalmente) fare una copia del unique_ptr:

Ptr p = v[0]; 

allora scoprirete al momento della compilazione. Non causerà un errore di runtime. Il tuo caso d'uso è il motivo per cui è stato creato container<unique_ptr<T>>. Le cose dovrebbero funzionare, e se non lo fanno, il problema appare in fase di compilazione invece che in fase di esecuzione. Quindi, codice via, e se non capisci l'errore di compilazione, allora fai un'altra domanda qui.

+0

Okay, penso che chiarisca le cose per me. Ho avuto l'abitudine di usare la nuova funzione for_each con un lambda il cui parametro è l'elemento passato per valore, NON per riferimento, ma suppongo che dovrò fare riferimento ad elementi unique_ptr se voglio evitare un tentativo copia/sposta. Post scriptum se cancello una volta l'iteratore e prendo un riferimento a quel risultato, presumo che questo eviti una copia tentata? Voglio dire: 'per (Contenitore :: iteratore it = container.begin(); it! = Container.end(); it ++) { unique_ptr & element = &*it; // Nessun tentativo di copia? } Grazie Howard, btw. –

+0

Sì, penso che dovrebbe funzionare bene. Sebbene tu abbia un extra '&' nel tuo codice. Ma il compilatore ti dirà dove. –

+0

Dovresti essere in grado di dereferenziarlo a: blah & element = ** it; ancora senza una copia, penso. (Probabilmente più utile.) –

32

Con auto e la gamma-based per-loop di C++ 11 questo diventa relativamente elegante:

std::vector< std::unique_ptr<YourClass>> pointers; 
for(auto&& pointer : pointers) { 
    pointer->functionOfYourClass(); 
} 

Il riferimento & alla std::unique_ptr evita la copia e si può utilizzare il uniqe_ptr senza dereferenziazione.

+0

Qualcuno sa se c'è una differenza tra l'uso di 'auto &' e 'auto &&' in questo caso? Questo riferimento suggerisce il doppio e http://en.cppreference.com/w/cpp/language/range-for, entrambi sembrano compilare – austinmarton

+0

Buona domanda. Ho trovato [questo collegamento] (http://en.cppreference.com/w/cpp/language/auto) (vedere Spiegazione/1) che suggerisce che 'auto &&' può funzionare come lvalue e rvalue a seconda dell'inizializzatore. Adattare l'esempio di conseguenza. – Pascal

Problemi correlati