2011-12-22 5 views
7

dado el ejemplo:¿Implicaciones de usar un ampersand antes de un nombre de función en C++?

inline string &GetLabel() { 
     return m_Label; 
}; 

Dónde m_Label es una variable miembro de clase privada.

La forma en que creo que la entiendo, esta función devolverá una referencia a la variable m_Label. ¿Cuáles serían las implicaciones de usar esto en mi programa y sería mejor simplemente devolver el valor, en lugar de la referencia? ¡Gracias!

Respuesta

6

Devuelve una referencia al miembro privado.

Hay muchos casos en que esto es deseable, pero debe tenerse cuidado.

IMO por lo general no es una buena idea devolver una copia de un objeto interno que no sea de tipo integral, por razones de rendimiento general. Sí, lo sé, la optimización prematura no es buena, pero esto no es realmente una optimización, es solo una buena práctica de desempeño que le permite al que llama determinar las implicaciones del rendimiento; si quiere una copia, simplemente no puede declarar la variable que la está asignando como referencia.

Hay 2 reglas generales que usan aquí:

1) Si no desea que la persona que llama para poder modificar el objeto privado directamente, declarar el valor de retorno como una referencia constante:

inline const string& GetLabel() const{ return m_Label; } 

2) Una persona que llama nunca debe almacenar la referencia devuelta por un método de clase, solo debe usarse localmente donde se garantiza que el objeto primario está dentro del alcance.

Si por alguna razón necesita que las personas que llaman puedan almacenar una referencia a sus objetos internos, use punteros inteligentes en su lugar.

11

El ampersand no está antes del nombre de la función sino del tipo de devolución. devuelve una referencia a string.

La implicación de esto es que una persona que llama de esta función podría modificar el valor de m_label a través de la referencia. Por otro lado, evita copiar la cadena. Es posible que desee la referencia y la función que se const, así:

inline const string& GetLabel() const 
{ 
    return m_Label; 
} 

mejor de ambos mundos. Evita la copia, pero las personas que llaman no pueden cambiar su objeto.

+0

De hecho, es probable que desee tanto las versiones const como las no const. – ildjarn

+0

@ildjam Eso es parcialmente cierto. Por lo general, solo deseará proporcionar la versión const, a menos que tenga una razón para querer permitir que las personas que llaman modifiquen el objeto directamente. Si proporciona la versión no const, entonces también debe proporcionar la versión const, para que pueda obtener acceso de solo lectura donde tenga una referencia constante al objeto principal. – Gerald

+1

@Gerald: Lo siento, debería aclarar, lo que quise decir es que, si quieres la versión no const que devuelve una referencia, entonces seguramente también querrás una versión de const. – ildjarn

1

Estás en lo correcto. Es una referencia al miembro de cuerda.

La implicación será que si un llamador fuera a asignar un valor o modificar la cadena devuelta, también estaría modificando la variable miembro. Si esta no es la intención, es posible que desee devolver una copia por valor para evitar romper la encapsulación.

2

Devolver una referencia significa que el código de llamada puede modificar el valor de su variable miembro después de regresar. Eso es muy peligroso, a menos que tengas la intención de que eso suceda.

Mejor es una referencia const, o devolver por valor (sin el &).

2

Una implicación es que si el objeto de cerramiento se destruye, la referencia no es válida:

Object* o = new Object; 
string& label = o->GetLabel(); 
delete o; 
// label becomes a dangling reference here. 

Otra implicación es que una persona que llama puede modificar la cadena. Puede remediarlo devolviendo una referencia constante.

Cuestiones relacionadas