[c++] La pratica di restituire una variabile di riferimento C ++, il male?



7 Answers

No. No, no, mille volte no.

Qual è il male sta facendo riferimento ad un oggetto allocato dinamicamente e perdendo il puntatore originale. Quando si new un new oggetto, si assume l'obbligo di disporre di delete garantita.

Ma date un'occhiata, ad esempio, operator<< : che deve restituire un riferimento, o

cout << "foo" << "bar" << "bletch" << endl ;

non funzionerà

Question

Questo è un po 'soggettivo penso; Non sono sicuro che il parere sarà unanime (ho visto molti frammenti di codice in cui vengono restituiti i riferimenti).

Secondo un commento a questa domanda, ho appena chiesto, per quanto riguarda i riferimenti di inizializzazione , restituire un riferimento può essere malvagio perché, [come ho capito] rende più facile perdere l'eliminazione, che può portare a perdite di memoria.

Questo mi preoccupa, come ho seguito degli esempi (a meno che non mi stia immaginando le cose) e l'ho fatto in un discreto numero di posti ... Ho frainteso? È cattivo? Se è così, quanto male?

Sento che grazie al mio bagaglio di riferimenti e puntatori, unito al fatto che sono nuovo al C ++ e alla totale confusione su cosa usare quando, le mie applicazioni devono essere fatiche della memoria ...

Inoltre, capisco che l'utilizzo di puntatori intelligenti / condivisi è generalmente accettato come il modo migliore per evitare perdite di memoria.




"restituire un riferimento è male perché, semplicemente [come ho capito] rende più facile perdere l'eliminazione"

Non vero. Restituire un riferimento non implica la semantica della proprietà. Cioè, solo perché lo fai:

Value& v = thing->getTheValue();

... non significa che ora possiedi la memoria a cui fa riferimento v;

Tuttavia, questo è un codice orribile:

int& getTheValue()
{
   return *new int;
}

Se stai facendo qualcosa del genere perché "non hai bisogno di un puntatore su quell'istanza" allora: 1) basta dereferenziare il puntatore se hai bisogno di un riferimento, e 2) alla fine avrai bisogno del puntatore, perché devi abbinare un nuovo con una cancellazione, e hai bisogno di un puntatore per chiamare eliminare.




    Class Set {
    int *ptr;
    int size;

    public: 
    Set(){
     size =0;
         }

     Set(int size) {
      this->size = size;
      ptr = new int [size];
     }

    int& getPtr(int i) {
     return ptr[i];  // bad practice 
     }
  };

la funzione getPtr può accedere alla memoria dinamica dopo la cancellazione o anche un oggetto nullo. Che può causare eccezioni di accesso non valido. Invece getter e setter dovrebbero essere implementati e le dimensioni devono essere verificate prima di tornare.




La cosa migliore è creare un oggetto e passarlo come parametro riferimento / puntatore a una funzione che assegna questa variabile.

Allocare l'oggetto in funzione e restituirlo come riferimento o puntatore (il puntatore è più sicuro comunque) è una cattiva idea a causa della liberazione della memoria alla fine del blocco funzione.




Non solo non è malvagio, a volte è essenziale. Ad esempio, sarebbe impossibile implementare l'operatore [] di std :: vector senza utilizzare un valore di riferimento.




Aggiunta alla risposta accettata:

struct immutableint {
    immutableint(int i) : i_(i) {}

    const int& get() const { return i_; }
private:
    int i_;
};

Direi che questo esempio non va bene e dovrebbe essere evitato se possibile. Perché? È molto facile finire con un riferimento ciondolante .

Per illustrare il punto con un esempio:

struct Foo
{
    Foo(int i = 42) : boo_(i) {}
    immutableint boo()
    {
        return boo_;
    }  
private:
    immutableint boo_;
};

entrando nella zona di pericolo:

Foo foo;
const int& dangling = foo.boo().get(); // dangling reference!



Informazioni su codice orribile:

int& getTheValue()
{
   return *new int;
}

Quindi, in effetti, il puntatore della memoria ha perso dopo il ritorno. Ma se usi shared_ptr in questo modo:

int& getTheValue()
{
   std::shared_ptr<int> p(new int);
   return *p->get();
}

La memoria non viene persa dopo il ritorno e sarà liberata dopo l'assegnazione.




Non è male. Come molte cose in C ++, è buono se usato correttamente, ma ci sono molte insidie ​​che dovresti sapere quando lo usi (come restituire un riferimento a una variabile locale).

Ci sono cose buone che possono essere raggiunte con esso (come map [nome] = "ciao mondo")




Related