referencias referencia que punteros puntero por paso pasar parametro funciones estructura declarar datos con como apuntadores c++ reference class-members

c++ - que - ¿Debo preferir los punteros o las referencias en los datos de los miembros?



que es un puntero en c (9)

Este es un ejemplo simplificado para ilustrar la pregunta:

class A {}; class B { B(A& a) : a(a) {} A& a; }; class C { C() : b(a) {} A a; B b; };

Así que B es responsable de actualizar una parte de C. Ejecuté el código a través de la pelusa y me zumbó sobre el miembro de referencia: lint#1725 . Esto habla de cuidar las copias y asignaciones predeterminadas, lo que es justo, pero la copia y la asignación predeterminadas también son malas con los punteros, por lo que hay poca ventaja.

Siempre trato de usar referencias donde puedo ya que los indicadores desnudos introducen incertidumbre sobre quién es responsable de borrar ese puntero. Prefiero incrustar objetos por valor, pero si necesito un puntero, uso auto_ptr en los datos de miembro de la clase propietaria del puntero y paso el objeto como referencia.

Por lo general, solo uso un puntero en los datos del miembro cuando el puntero podría ser nulo o podría cambiar. ¿Hay alguna otra razón para preferir los punteros a las referencias de los miembros de datos?

¿Es cierto que un objeto que contiene una referencia no debería ser asignable, ya que una referencia no debería cambiarse una vez inicializada?


Por lo general, solo uso un puntero en los datos del miembro cuando el puntero podría ser nulo o podría cambiar. ¿Hay alguna otra razón para preferir los punteros a las referencias de los miembros de datos?

Sí. Legibilidad de tu código Un puntero hace que sea más obvio que el miembro es una referencia (irónicamente :)), y no un objeto contenido, porque cuando lo usa tiene que des-referenciarlo. Sé que algunas personas piensan que está pasado de moda, pero sigo pensando que simplemente evita la confusión y los errores.


Como todos parecen estar dando reglas generales, ofreceré dos:

  • Nunca, nunca use referencias de uso como miembros de la clase. Nunca lo he hecho en mi propio código (excepto para probarme a mí mismo que tenía razón en esta regla) y no puedo imaginar un caso en el que lo haría. La semántica es muy confusa, y realmente no es para lo que se diseñaron las referencias.

  • Siempre, siempre, use referencias cuando pase parámetros a funciones, excepto para los tipos básicos, o cuando el algoritmo requiera una copia.

Estas reglas son simples y me han sido útiles. Dejo las reglas sobre el uso de punteros inteligentes (pero, por favor, no auto_ptr) como miembros de la clase a otros.


En algunos casos importantes, la asignación es simplemente innecesaria. A menudo, estos son envoltorios de algoritmos livianos que facilitan el cálculo sin abandonar el alcance. Dichos objetos son candidatos principales para los miembros de referencia ya que puede estar seguro de que siempre tienen una referencia válida y nunca necesitan copiarse.

En tales casos, asegúrese de que el operador de asignación (y a menudo también el constructor de copia) no sea utilizable (heredando de boost::noncopyable o declarándolos privados).

Sin embargo, como los usuarios ya han comentado, lo mismo no es cierto para la mayoría de los otros objetos. Aquí, usar miembros de referencia puede ser un gran problema y generalmente se debe evitar.


Evite a los miembros de referencia, ya que restringen lo que la implementación de una clase puede hacer (incluyendo, como usted menciona, prevenir la implementación de un operador de asignación) y no proporcionan ningún beneficio a lo que la clase puede proporcionar.

Problemas de ejemplo:

  • se ve forzado a inicializar la referencia en la lista de inicializadores de cada constructor: no hay forma de factorizar esta inicialización en otra función ( hasta C ++ 0x, de todos modos editar: C ++ ahora tiene constructores delegados )
  • la referencia no puede ser rebote o ser nula. Esto puede ser una ventaja, pero si el código necesita cambiar para permitir la reenlace o para que el miembro sea nulo, todos los usos del miembro deben cambiar.
  • a diferencia de los miembros del puntero, las referencias no pueden reemplazarse fácilmente por punteros inteligentes o iteradores ya que la refactorización puede requerir
  • Cada vez que se utiliza una referencia, se parece al tipo de valor (operador, etc.), pero se comporta como un puntero (puede colgar), por lo que Google Style Guide lo desalienta

Los objetos raramente deberían permitir asignar y otras cosas como la comparación. Si considera algún modelo comercial con objetos como ''Departamento'', ''Empleado'', ''Director'', es difícil imaginar un caso en el que un empleado será asignado a otro.

Entonces, para objetos comerciales es muy bueno describir las relaciones uno a uno y uno a muchos como referencias y no como punteros.

Y, probablemente, está bien describir una relación uno o cero como un puntero.

Entonces no ''no podemos asignar'' entonces factor.
Muchos programadores simplemente se acostumbran con los punteros y es por eso que encontrarán cualquier argumento para evitar el uso de la referencia.

Tener un puntero como miembro lo obligará a usted o a un miembro de su equipo a verificar el puntero una y otra vez antes de usarlo, con el comentario "por las dudas". Si un puntero puede ser cero, entonces el puntero probablemente se use como un tipo de bandera, lo cual es malo, ya que cada objeto debe jugar su propio rol.


Mi propia regla de oro:

  • Utilice un miembro de referencia cuando desee que la vida de su objeto dependa de la vida de otros objetos : es una manera explícita de decir que no permite que el objeto esté vivo sin una instancia válida de otra clase, debido a que no asignación y la obligación de obtener la inicialización de referencias a través del constructor. Es una buena forma de diseñar tu clase sin asumir nada acerca de si su instancia es miembro o no de otra clase. Solo asumes que sus vidas están directamente relacionadas con otras instancias. Le permite cambiar más tarde cómo usa su instancia de clase (con una instancia nueva, como una instancia local, como miembro de la clase, generada por un grupo de memoria en un administrador, etc.)
  • Use el puntero en otros casos : cuando desee que el miembro se modifique más tarde, use un puntero o un puntero const para asegurarse de leer solo la instancia apuntada. Si se supone que ese tipo se puede copiar, no puede usar referencias de todos modos. A veces también necesita inicializar el miembro después de una llamada a función especial (init (), por ejemplo) y luego simplemente no tiene más remedio que usar un puntero. PERO: ¡utilice afirma en toda su función de miembro para detectar rápidamente el estado del puntero incorrecto!
  • En los casos en que desee que la duración del objeto dependa de la duración de un objeto externo, y también necesita que ese tipo sea copiable, utilice los miembros del puntero pero el argumento de referencia en el constructor. De esta forma, indicará durante la construcción que la duración de este objeto depende en la duración del argumento, PERO la implementación utiliza punteros para que aún se pueda copiar. Siempre que estos miembros solo cambien por copia, y su tipo no tenga un constructor predeterminado, el tipo debe cumplir ambos objetivos.

No recomiendo a los miembros de los datos de referencia porque nunca se sabe quién se va a derivar de su clase y qué es lo que podrían querer hacer. Puede que no quieran hacer uso del objeto al que se hace referencia, pero al ser una referencia, los obligó a proporcionar un objeto válido. Me he hecho esto lo suficiente como para dejar de usar miembros de datos de referencia.


Sí a: ¿Es cierto que un objeto que contiene una referencia no debe ser asignable, ya que una referencia no se debe cambiar una vez inicializada?

Mis reglas generales para los miembros de datos:

  • nunca use una referencia, ya que evita la asignación
  • si tu clase es responsable de eliminar, usa scoped_ptr de boost (que es más seguro que un auto_ptr)
  • de lo contrario, use un puntero o puntero const