Se la proprietà dell'oggetto gestito non viene trasferita (e poiché è una unique_ptr
, la proprietà non può essere condivisa), allora è più corretto separare la logica nella funzione chiamata dal concetto di proprietà. Lo facciamo chiamando per riferimento.
Questo è un modo contorto per dire:
Data:
std::unique_ptr<Thing> thing_ptr;
per cambiare la Cosa:
// declaration
void doSomethingWith(Thing& thing);
// called like this
doSomethingWith(*thing_ptr);
di utilizzare la cosa senza modificarlo.
// declaration
void doSomethingWith(const Thing& thing);
// called like this
doSomethingWith(*thing_ptr);
L'unica volta che ci si vuole parlare della unique_ptr
nella firma funzione sarebbe se si stesse trasferendo la proprietà:
// declaration
void takeMyThing(std::unique_ptr<Thing> p);
// call site
takeMyThing(std::move(thing_ptr));
Non hai mai bisogno di fare questo:
void useMyThing(const std::unique_ptr<Thing>& p);
Il motivo per cui questa sarebbe una cattiva idea è che se confonde la logica di useMyThing con il concetto di proprietà, restringendo così l'ambito di riutilizzo.
considerare:
useMyThing(const Thing& thing);
Thing x;
std::unique_ptr<Thing> thing_ptr = makeAThing();
useMyThing(x);
useMyThing(*thing_ptr);
Aggiornamento:
Notando l'aggiornamento alla domanda - la memorizzazione (non proprietario) i riferimenti a questo oggetto.
Un modo per fare ciò è in effetti memorizzare un puntatore. Tuttavia, i puntatori soffrono della possibilità di un errore logico in quanto possono essere legalmente nulli. Un altro problema con i puntatori è che non funzionano bene con std:: algorithms
e contenitori - che richiedono funzioni di confronto personalizzate e simili.
C'è un modo std::-compliant
per fare questo - il std::reference_wrapper<>
Quindi, piuttosto che questo:
std::vector<Thing*> my_thing_ptrs;
fare questo:
std::vector<std::reference_wrapper<Thing>> my_thing_refs;
Dal std::reference_wrapper<T>
definisce un operatore T&
, è possibile utilizzare l'oggetto reference_wrapped
in qualsiasi espressione che si aspetterebbe da un T
.
ad esempio:
std::unique_ptr<Thing> t1 = make_thing();
std::unique_ptr<Thing> t2 = make_thing();
std::unique_ptr<Thing> t3 = make_thing();
std::vector<std::reference_wrapper<const Thing>> thing_cache;
store_thing(*t1);
store_thing(*t2);
store_thing(*t3);
int total = 0;
for(const auto& t : thing_cache) {
total += value_of_thing(t);
}
dove:
void store_thing(const Thing& t) {
thing_cache.push_back(std::cref(t));
}
int value_of_thing(const Thing& t) {
return <some calculation on t>;
}
perché non passare il riferimento dell'oggetto unique_ptr in giro? – Zaiborg
Non si può avere un 'unique_ptr' e un' shared_ptr' gestiscono entrambi lo stesso oggetto. –
passando un riferimento all'oggetto indicato, è una buona idea. –