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;
};
Entonces B es responsable de actualizar una parte de C. Ejecuté el código a través de lint y se quejó sobre el miembro de referencia: lint # 1725 . Esto habla de tener cuidado con la copia predeterminada y las asignaciones, lo cual es bastante justo, pero la copia predeterminada y la asignación también son malas con los punteros, por lo que hay poca ventaja allí.
Siempre trato de usar referencias donde puedo, ya que los punteros desnudos introducen incertidumbre sobre quién es responsable de eliminar ese puntero. Prefiero incrustar objetos por valor, pero si necesito un puntero, uso auto_ptr en los datos de miembros de la clase que posee el puntero y paso el objeto como referencia.
En general, solo usaría 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 punteros sobre referencias para miembros de datos?
¿Es cierto decir que un objeto que contiene una referencia no debe ser asignable, ya que una referencia no debe cambiarse una vez inicializada?
fuente
Respuestas:
Evite los miembros de referencia, ya que restringen lo que puede hacer la implementación de una clase (incluido, como usted menciona, evitar la implementación de un operador de asignación) y no proporcionan beneficios a lo que la clase puede proporcionar.
Problemas de ejemplo:
hasta C ++ 0x, de todos modosedite: C ++ ahora tiene delegadores de constructores ).
operador, etc.), pero se comporta como un puntero (puede colgar), por lo que, por ejemplo, la Guía de estilo de Google lo desalientafuente
Mi propia regla de oro:
fuente
Los objetos rara vez deberían permitir la asignación y otras cosas como la comparación. Si considera algún modelo de negocio con objetos como 'Departamento', 'Empleado', 'Director', es difícil imaginar un caso en el que un empleado sea asignado a otro.
Por lo tanto, para los objetos comerciales es muy bueno describir las relaciones uno a uno y uno a muchos como referencias y no como indicadores.
Y probablemente esté bien describir una relación de uno o cero como un puntero.
Entonces no 'no podemos asignar' entonces factor.
Muchos programadores simplemente se acostumbran a los punteros y es por eso que encontrarán cualquier argumento para evitar el uso de referencias.
Tener un puntero como miembro lo obligará a usted o al miembro de su equipo a verificar el puntero una y otra vez antes de usarlo, con un comentario "por si acaso". Si un puntero puede ser cero, entonces el puntero probablemente se usa como un tipo de indicador, lo cual es malo, ya que cada objeto tiene que desempeñar su propio papel.
fuente
Utilice referencias cuando pueda y punteros cuando sea necesario.
fuente
En algunos casos importantes, la asignabilidad simplemente no es necesaria. Estos son a menudo envoltorios de algoritmos livianos que facilitan el cálculo sin salir del alcance. Dichos objetos son candidatos principales para miembros de referencia, ya que puede estar seguro de que siempre tienen una referencia válida y nunca necesitan ser copiados.
En tales casos, asegúrese de que el operador de asignación (y, a menudo, también el constructor de la copia) no se pueda usar (heredando
boost::noncopyable
o declarándolos privados).Sin embargo, como los usuarios ya comentaron, lo mismo no es cierto para la mayoría de los otros objetos. Aquí, el uso de miembros de referencia puede ser un gran problema y, por lo general, debe evitarse.
fuente
Como todo el mundo parece estar entregando reglas generales, ofreceré dos:
Nunca, nunca use referencias de uso como miembros de la clase. Nunca lo hice en mi propio código (excepto para demostrarme a mí mismo que estaba en lo cierto en esta regla) y no puedo imaginar un caso en el que lo haría. La semántica es demasiado confusa, y realmente no es para lo que se diseñaron las referencias.
Siempre, siempre, use referencias cuando pase parámetros a funciones, excepto los tipos básicos, o cuando el algoritmo requiera una copia.
Estas reglas son simples y me han servido de mucho. Dejo hacer reglas sobre el uso de punteros inteligentes (pero, por favor, no auto_ptr) como miembros de la clase para otros.
fuente
Sí a: ¿Es cierto decir que un objeto que contiene una referencia no debe ser asignable, ya que una referencia no debe cambiarse una vez inicializada?
Mis reglas generales para los miembros de datos:
fuente
Si. Legibilidad de su 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, debe desreferenciarlo. Sé que algunas personas piensan que está pasado de moda, pero sigo pensando que simplemente evita la confusión y los errores.
fuente
Aconsejo a los miembros de datos de referencia que nunca sepan quién va a derivar de su clase y qué podrían querer hacer. Es posible que no quieran hacer uso del objeto referenciado, pero al ser una referencia, los ha obligado a proporcionar un objeto válido. Me he hecho esto lo suficiente como para dejar de usar miembros de datos de referencia.
fuente
Si entiendo la pregunta correctamente ...
Referencia como parámetro de función en lugar de puntero: como señaló, un puntero no deja en claro quién posee la limpieza / inicialización del puntero. Prefiere un punto compartido cuando desea un puntero, es parte de C ++ 11 y un punto débil cuando la validez de los datos no está garantizada durante la vida útil de la clase que acepta los datos señalados .; también es parte de C ++ 11. El uso de una referencia como parámetro de función garantiza que la referencia no sea nula. Tienes que subvertir las características del lenguaje para evitar esto, y no nos importan los codificadores de cañones sueltos.
Referencia aa variable miembro: Como se indicó anteriormente con respecto a la validez de los datos. Esto garantiza que los datos señalados, luego referenciados, son válidos.
Mover la responsabilidad de la validez de la variable a un punto anterior en el código no solo limpia el código posterior (la clase A en su ejemplo), sino que también lo deja claro para la persona que lo usa.
En su ejemplo, que es un poco confuso (realmente trataría de encontrar una implementación más clara), la A utilizada por B está garantizada durante toda la vida de la B, ya que B es miembro de A, por lo que una referencia refuerza esto y es (quizás) más claro.
Y por si acaso (que es una campana de baja probabilidad, ya que no tendría ningún sentido en el contexto de sus códigos), otra alternativa, usar un parámetro A no referenciado, sin puntero, copiaría A y haría que el paradigma fuera inútil: I Realmente no creo que te refieres a esto como una alternativa.
Además, esto también garantiza que no puede cambiar los datos a los que se hace referencia, donde se puede modificar un puntero. Un puntero constante funcionaría solo si el puntero / referenciado a los datos no fuera mutable.
Los punteros son útiles si no se garantizó que el parámetro A para B se estableciera o si pudiera reasignarse. Y a veces un puntero débil es demasiado detallado para la implementación, y un buen número de personas no sabe qué es un débil_ptr o simplemente no les gusta.
Separe esta respuesta, por favor :)
fuente