2010-07-05 16 views
19

Estoy queriendo asegurarme de que entiendo correctamente el pass-by-value vs pass-by-reference. En particular, estoy buscando las versiones de prefijo/postfijo del operador de incremento ++ para un objeto.Operadores de incremento de prefijo/postfijo

Supongamos que tenemos la siguiente clase X:

class X{ 
private: 
    int i; 
public: 
X(){i=0;} 
X& operator ++(){ ++i; return *this; } //prefix increment 

X operator ++ (int unused){ //postfix increment 
    X ret(*this); 
    i++; 
    return ret; 
} 

operator int(){ return i; } //int cast 
}; 

En primer lugar, he implementado los operadores de incremento/postfix prefijo correctamente?

En segundo lugar, ¿qué tan eficiente es la memoria el operador postfix, en comparación con el operador de prefijo? Específicamente, ¿cuántas copias de objetos X se crean cuando se utiliza cada versión del operador?

Una explicación de lo que sucede exactamente con retorno por referencia vs retorno por valor puede ayudarme a entender.


Editar: Por ejemplo, con el siguiente código ...

X a; 
X b=a++; 

... A y B son ahora los alias?

+0

No hay necesidad de postfix-incrementar 'i' en el operador de posfijo. De hecho, haría lo que [sugiere FredOverflow] (http://stackoverflow.com/questions/3181211/3181359#3181359) y llamo a la versión de prefijo. IMO que es de hecho más idiomático que volver a implementar el incremento (aunque la implementación es trivial aquí). _Y deshazte de ese operador implícito de conversión. De lo contrario, te lastimará. (La tercera y última vez que escribí un operador de conversión implícita fue en 2001 y uno o dos años más tarde descubrí que causaba errores sutiles y lo eliminaba, como todos los anteriores. BTDTGTLS) – sbi

Respuesta

17

Esta es una implementación correcta. Es típico que un operador de postfix empeore su rendimiento porque debe crear otra copia antes de hacer el incremento (y es por eso que tengo el hábito de usar siempre el prefijo a menos que necesite algo más).

Con devolución por referencia, devuelve una referencia de l valor al objeto actual. El compilador típicamente implementaría esto devolviendo la dirección del objeto actual. Esto significa que devolver el objeto es tan simple como devolver un número.

Sin embargo, con retorno por valor, se debe hacer una copia. Esto significa que hay más información para copiar durante la devolución (en lugar de solo una dirección), así como también un constructor de copia para llamar. Aquí es donde entra en acción su éxito.

La eficacia de su implementación se ve a la par de las implementaciones típicas.

EDIT: Con respecto a su anexo, no, no son alias. Has creado dos objetos separados. Cuando regresa por valor (y cuando creó un nuevo objeto desde el operador de incremento de postfix) este nuevo objeto se coloca en una ubicación de memoria distinta.

Sin embargo, en el siguiente código, a y b son alias:

int a = 0; 
int& b = ++a; 

b es una dirección que hace referencia a.

+2

Correcto en general, módulo posible Valor de retorno Optimización (http://en.wikipedia.org/wiki/Return_value_optimization). –

2

Sus operadores están implementados correctamente.

En el operador de prefijo, no se realizan copias de X.

En el operador postfix, se realiza una copia para ret, y potencialmente se realiza otra copia al regresar de la función, pero todos los compiladores eliminarán esta copia.

15

Es más idiomática para llamar al incremento prefijo del objeto mismo en el incremento postfix:

X operator++(int) 
{ 
    X copy(*this); 
    ++*this;   // call the prefix increment 
    return copy; 
} 

La lógica de incrementar un objeto X es así únicamente contenido dentro de la versión de prefijo.

+0

Sí, esto me libera de publicar la misma corrección. '+ 1' de mí. – sbi