2010-09-19 19 views
5

Si tengo una clase que tiene muchas variables de miembro int, float y enum, ¿se considera eficiente y/o buena práctica devolverlas como referencias en lugar de copias, y devolver referencias constantes donde no se deben hacer cambios? ¿O hay alguna razón por la que debería devolverlos como copias?¿Es una buena idea devolver siempre las referencias de los getters variables miembro?

+1

me hizo una pregunta relacionada http://stackoverflow.com/q/3740876/15161 - tal vez las respuestas no será de ayuda. – slashmais

+0

Pregunta incorrecta. Mejor pregunta: [¿Es una mala idea tener compradores para todos sus miembros de datos?] (Http://www.idinews.com/quasiClass.pdf) – sbi

Respuesta

7

No hay motivo para devolver tipos primitivos como int y float como referencia, a menos que desee permitir su modificación. Devolverlos por referencia es en realidad menos eficiente porque no ahorra nada (int sy los punteros suelen tener el mismo tamaño) mientras que la eliminación de referencias realmente agrega sobrecarga.

+0

¡Eso fue útil, gracias! – Jengerer

+0

Tengo una pregunta, sin embargo. ¿Qué se debe considerar una compensación justa para usar un puntero o referencia? Por ejemplo, un doble es 8 bytes, y un puntero a un doble es 4 bytes. ¿Los gastos generales añadidos para desreferenciar superan al tamaño más pequeño? – Jengerer

+1

Sí. Mi regla de oro es devolver tipos primitivos directamente, incluso 'double'. Las clases se devuelven como referencias const, incluso las pequeñas. –

1

Esto es probablemente una cuestión de estilo o preferencia. Una razón para no devolver referencias es porque está utilizando getters y setters para permitirle cambiar la implementación de esos miembros. Si cambió un miembro privado a otro tipo, o lo eliminó por completo porque puede ser computado, entonces ya no tiene la capacidad de devolver una referencia, ya que no hay nada para referenciar.

Por otro lado, devolver referencias para tipos no triviales (clases compuestas) puede acelerar su código un poco más que hacer una copia, y puede permitir que esos miembros se asignen a través de la referencia devuelta (si lo desea).

4

Si son referencias constantes, quizás esté bien. Si no son referencias constantes, probablemente no.

En cuanto a la eficiencia, en una máquina de 64 bits, las referencias serán cantidades de 64 bits (punteros disfrazados); int y float y enum serán más pequeños. Si devuelve una referencia, está forzando un nivel de indirección; es menos eficiente.

Por lo tanto, especialmente para los tipos incorporados como valores de retorno, generalmente es mejor devolver el valor en lugar de una referencia.

+0

Gracias por la respuesta, que ayudó! – Jengerer

4

algunos casos es necesario:

Mira sobrecargado operator[] para cualquier clase. Por lo general tiene dos versiones. La versión mutante debe devolver una referencia.

int &operator[](int index);   // by reference 
int operator[](int index) const;  // by value 

En general, está bien para permitir el acceso a los miembros de la clase de entidades de confianza, por ejemplo, por una clase amigos. En caso de que estas entidades de confianza también necesiten modificar el estado, referencias o indicadores para los miembros de la clase, son las únicas opciones que tiene.

En muchos casos, las referencias generalmente simplifican la sintaxis, por ejemplo, cuando 'v' es el vector STL.

v.at(1) = 2 vs *(v.at(1)) = 2; 
0

Casi, las referencias const son mejores. Para los ints y esos no hay ningún punto porque querrías que se cambien o porque son del mismo tamaño (o casi) como referencia.

Así que sí, es una buena idea. Prefiero otro idioma o piratear mis propias cosas en C++ y permitir que la var sea pública (una vez más es solo mi propio material)

+0

Claro, podría hacerlos públicos, pero algunos de ellos no deberían ser de acceso público, ya que tienen ciertas restricciones por el valor que se les puede dar, por lo que los envuelvo con setters/getters para hacer cumplir esas reglas. ¡Gracias por la respuesta! – Jengerer

+0

@Jenger: para reglas muy simples y autónomas, puede dejar que el sistema de tipos lo ayude. Por ejemplo, en lugar de un campo 'int digit' y un setter que comprueba que los dígitos están entre 0 y 9, puede escribir su propio tipo' digit' que solo tiene los valores de 0 a 9 y luego usar un campo público 'digit' en tu clase, sin un getter y un setter. – fredoverflow

+0

Jengerer: En mi propio código digo que haré eso por todas partes porque es mío y nadie más (nadie tiene que tocarlo). Además, si la clase es trivial, lo haré en el trabajo y, hasta el momento, nadie se ha quejado. Pero realmente no hago C++ en el trabajo –

0

Esta es una pregunta de rendimiento principalmente, pero desde el punto de vista de la robustez diría es preferible devolver valores en lugar de referencias de referencias. La razón es que incluso las referencias const debilitan la encapsulación.Considere esto:

struct SomeClass 
{ 
    std::vector<int> const & SomeInts() const; 
    void AddAnInt (int i); // Adds an integer to the vector of ints. 
private: 
    std::vector<int> m_someInts; 
}; 

bool ShouldIAddThisInt(int i); 

void F (SomeClass & sc) 
{ 
    auto someInts = sc.SomeInts(); 
    auto end = someInts.end(); 
    for (auto iter = someInts.begin(); iter != end; ++iter) 
    { 
     if (ShouldIAddThisInt(*iter)) 
     { 
     // oops invalidates the iterators 
     sc.AddAnInt (*iter); 
     } 
    } 
} 

Así que en caso de que tenga sentido semántico y podemos evitar asignaciones dinámicas excesivas prefiero retorno por valor.

0

Los captadores son para emisiones de una clase digamos Exhaust Car.emit(), donde el auto acaba de crear el Exhaust.

Si usted está obligado a escribir const Seat& Car.get_front_seat()
para tener más tarde sentarse en el Driver, se nota inmediatamente que algo está mal.
Correcly, prefiero escribir Car.get_in_driver(Driver)
que luego llama directamente al seat.sit_into(Driver).

Este segundo método evita fácilmente esas situaciones incómodas cuando get_front_seat pero la puerta está cerrada y prácticamente empuja el controlador a través de la puerta cerrada. Recuerde, ¡solo ha pedido un asiento! :)

En general: siempre devuelva por el valor (y confíe en la optimización del valor de retorno), o se da cuenta de que es hora de cambiar su diseño.

El fondo: clases fueron creadas para que los datos se pueden acoplar con su funcionalidad de acceso, localización de errores, etc. Por lo tanto nunca son clases de actividad, pero orientados a datos.

Otros errores: en C++ si devuelve algo por const ref, entonces puede olvidar fácilmente que es solo una referencia y una vez que su objeto se destruye puede quedar con una referencia no válida. De lo contrario, ese objeto se copiará una vez que abandona el getter de todos modos. Pero el compilador evita las copias innecesarias, ver Return Value Optimization.

Cuestiones relacionadas