shared_ptr e riferimenti in C ++
-
05-07-2019 - |
Domanda
I riferimenti in C ++ sono un costrutto conveneint che ci consente di semplificare il seguente codice C:
f(object *p){
//do something
}
int main(){
object* p = (object*) calloc(sizeof(object));
f(p);
}
a
f(object& o){
//do something
}
int main(){
object o = object();
f(o);
}
I puntatori condivisi sono un'altra comodità in C ++ che semplifica la gestione della memoria. Tuttavia, non sono sicuro di come passare un shared_ptr
a una funzione come f (object & amp; o)
che accetta argomenti per riferimento?
f(object& o){
//do something
}
int main(){
shared_ptr<object> p (new object());
f(*p);
}
Il puntatore condiviso verrà incrementato quando il suo oggetto viene passato in riferimento a una funzione?
Soluzione
Prendi un shared_ptr
per valore e il conteggio dei riferimenti aumenterà. Questo è più semplice quando digiti
:
typedef boost:shared_ptr<object> object_ptr;
void foo(object_ptr obj)
{
obj->/* stuff*/;
obj.reset(); //only resets this local copy, that means:
// reduce reference count (back to 1), and
// set obj to point at null.
}
int main(void)
{
object_ptr obj(new object());
foo(obj);
}
Ricorda che i riferimenti sono alias. Quando passi per riferimento, non stai passando puntatori, copie, ecc ..., stai aliasando un altro oggetto. (In realtà sono implementati come puntatori):
typedef boost:shared_ptr<object> object_ptr;
void foo(object_ptr& obj)
{
obj.reset(); // the references was never increased, since a copy has not
// been made, this *is* obj in main. so the reference
// goes to 0, and obj is deleted
}
int main(void)
{
object_ptr obj(new object);
foo(obj); // after this, obj has been reset!
}
Ricorda sempre di essere const
corretto, per evitare errori:
typedef boost:shared_ptr<object> object_ptr;
void foo(const object_ptr& obj)
{
obj.reset(); // cannot do!
}
int main(void)
{
object_ptr obj(new object);
foo(obj);
}
Penso che dovresti preferire passare puntatori intelligenti come riferimenti quando possibile, per evitare incrementi e decrementi estranei (e copie e quant'altro).
Altri suggerimenti
Il puntatore condiviso verrà incrementato quando il suo oggetto viene passato in riferimento a una funzione?
No, mentre accedi al puntatore non elaborato e poi lo passi. Vuoi fare qualcosa di simile a questo:
f(shared_ptr<object> o){
//do something
}
int main(){
shared_ptr<object> p (new object());
f(p);
}
f(object& o){ //do something } int main(){ shared_ptr<object> p (new object()); f(*p); }
Il puntatore condiviso verrà incrementato quando il suo oggetto viene passato per riferimento a una funzione?
Nel codice sopra - no. p avrà il suo contatore di riferimento uguale a 1 in ogni momento. Puoi verificarlo in un debugger. Il contatore dei riferimenti di shared_ptr conta il numero di istanze shared_ptr che puntano allo stesso oggetto, non tiene traccia dei riferimenti creati chiamando l'operatore * (). E non è necessario, poiché p è garantito fino al termine dell'ambito e la chiamata di funzione è nello stesso ambito (o più profonda) p sarà lì durante l'intera chiamata a f (). Quindi va tutto bene.
... a meno che in f prendi l'indirizzo di o e conservi un posto che durerà dopo il ritorno di f . Questo dovresti evitare in ogni caso: passa il file shared_ptr se devi farlo.
Per prima cosa, dal punto di vista della funzionalità, i riferimenti in C ++ sono esattamente gli stessi dei puntatori. Il solo motivo per cui sono stati aggiunti al linguaggio è quello di rendere più naturale la sintassi del sovraccarico dell'operatore. (Ad esempio per consentire a uno di scrivere a + b invece di & amp; a + & amp; b)
I tuoi esempi di codice C e C ++ non sono assolutamente equivalenti. La versione C del tuo codice C ++ sarebbe:
f(object *p){
//do something
}
int main(){
object o;
object_constructor(&o);
f(&o);
object_destructor(&o);
}
In realtà, questo è il tipo di codice che il tuo compilatore C ++ genererà concettualmente.
Per quanto riguarda la tua seconda domanda: Sì, questo è il modo corretto di chiamare la funzione f. Il contatore del puntatore condiviso non verrà incrementato. Il puntatore effettivo all'oggetto verrà passato, come se non si stesse usando shared_ptr. Tuttavia, è sicuro, purché f non stia facendo nulla di strano. Ricorda solo che sta succedendo esattamente le stesse cose come se il parametro di f prendesse un puntatore anziché un riferimento. L'unica differenza è che il compilatore passa automagicamente l'indirizzo della variabile senza che tu debba usare esplicitamente & amp; operatore.
Personalmente non mi piace mai passare variabili per riferimento (passare per const const è ok però). Preferisco usare un puntatore invece perché rende più chiaro sul sito della chiamata che la funzione che stiamo chiamando potrebbe potenzialmente modificare il suo argomento (poiché il simbolo & amp; è visibile sul sito della chiamata).
Pace