¿Es mala la práctica de devolver una variable de referencia de C++?

Resuelto Nick Bolton asked hace 15 años • 16 respuestas

Creo que esto es un poco subjetivo; No estoy seguro de si la opinión será unánime (he visto muchos fragmentos de código donde se devuelven referencias).

Según un comentario sobre esta pregunta que acabo de hacer, con respecto a la inicialización de referencias , devolver una referencia puede ser malo porque, [según tengo entendido] hace que sea más fácil no eliminarla, lo que puede provocar pérdidas de memoria.

Esto me preocupa, ya que he seguido ejemplos (a menos que esté imaginando cosas) y he hecho esto en unos pocos lugares... ¿He entendido mal? ¿Es malo? Si es así, ¿qué tan malvado?

Siento que debido a mi mezcla de sugerencias y referencias, combinado con el hecho de que soy nuevo en C++ y la confusión total sobre qué usar y cuándo, mis aplicaciones deben ser un infierno de pérdida de memoria...

Además, entiendo que el uso de punteros inteligentes/compartidos generalmente se acepta como la mejor manera de evitar pérdidas de memoria.

Nick Bolton avatar Apr 15 '09 23:04 Nick Bolton
Aceptado

En general, devolver una referencia es perfectamente normal y ocurre todo el tiempo.

Si te refieres a:

int& getInt() {
    int i;
    return i;  // DON'T DO THIS.
}

Eso es todo tipo de males. La pila asignada idesaparecerá y no te referirás a nada. Esto también es malo:

int& getInt() {
    int* i = new int;
    return *i;  // DON'T DO THIS.
}

Porque ahora el cliente eventualmente tiene que hacer lo extraño:

int& myInt = getInt(); // note the &, we cannot lose this reference!
delete &myInt;         // must delete...totally weird and  evil

int oops = getInt(); 
delete &oops; // undefined behavior, we're wrongly deleting a copy, not the original

Tenga en cuenta que las referencias de rvalue siguen siendo solo referencias, por lo que todas las aplicaciones malvadas siguen siendo las mismas.

Si desea asignar algo que se encuentra más allá del alcance de la función, use un puntero inteligente (o en general, un contenedor):

std::unique_ptr<int> getInt() {
    return std::make_unique<int>(0);
}

Y ahora el cliente almacena un puntero inteligente:

std::unique_ptr<int> x = getInt();

Las referencias también están bien para acceder a cosas cuya vida útil se mantiene abierta en un nivel superior, por ejemplo:

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

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

Aquí sabemos que está bien devolver una referencia i_porque cualquier cosa que nos llame administra la vida útil de la instancia de clase, por lo que i_vivirá al menos ese tiempo.

Y, por supuesto, no hay nada de malo en simplemente:

int getInt() {
   return 0;
}

Si la vida útil debe dejarse en manos de la persona que llama y usted solo está calculando el valor.

Resumen: está bien devolver una referencia si la vida útil del objeto no finalizará después de la llamada.

GManNickG avatar Apr 15 '2009 16:04 GManNickG

No.

Lo malo es hacer referencia a un objeto asignado dinámicamente y perder el puntero original. Cuando adquieres newun objeto asumes la obligación de tener una garantía delete.

Pero eche un vistazo, por ejemplo operator<<: eso debe devolver una referencia, o

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

no funcionará.

Charlie Martin avatar Apr 15 '2009 16:04 Charlie Martin