A estas alturas su cabeza debe estar echando humo, y se preguntará cómo es posible que pudiera escribir una clase que funcionase sin saber nada acerca del constructor de copia. No obstante, recuerde que el constructor de copia sólo es necesario cuando la clase se pasa por valor. Si esto no va a ocurrir, entonces no lo necesita.
«Pero», puede decir, «si no defino el constructor de copia, el compilador lo creará por mí. ¿Cómo sé que un objeto nunca se pasará por valor?»
Existe una técnica simple para evitar el paso por valor:
declare un constructor de copia private
. Ni
siquiera necesita definirlo (sólo declararlo), a no ser que
un método o una función friend
necesite realizar un
paso por valor. Si el usuario intenta pasar o retornar el
objeto por valor, el compilador se quejará con un error
porque el constructor de copia es privado. El compilador ya
no puede crear un constructor de copia por defecto porque
explícitamente ya hay uno creado.
He aquí un ejemplo:
//: C11:NoCopyConstruction.cpp // Preventing copy-construction class NoCC { int i; NoCC(const NoCC&); // No definition public: NoCC(int ii = 0) : i(ii) {} }; void f(NoCC); int main() { NoCC n; //! f(n); // Error: copy-constructor called //! NoCC n2 = n; // Error: c-c called //! NoCC n3(n); // Error: c-c called } ///:~
Listado 11.10. C11/NoCopyConstruction.cpp
Note la utilización de la forma más general
NoCC(const NoCC&);
utilizando const
La sintaxis de referencias es más agradable que la de
punteros, aunque oculte significado al que lea el código
fuente. Por ejemplo, en la librería
iostreams
existe una versión
sobrecargada de la función get()
que
tiene como argumento un char &
, y su
cometido es modificar ese argumento y utilizarlo como el
valor que retorna get()
. No obstante,
si lee el código fuente de esta función, no es
inmediatamente obvio que la variable que se pasa como
argumento vaya a ser modificada:
char c; cin.get(c);
Parece que a la función se le pasa por valor, lo que sugiere que el argumento que se pasa no se modifica.
A causa de esto, es probablemente más seguro, desde el punto de vista de mantenimiento del código fuente, utilizar punteros que pasen la dirección del argumento que se desee modificar. Si siempre pasa direcciones como referencias constantes excepto cuando intenta modificar el argumento que se pasa a través de la dirección, donde pasaría un puntero no constante, entonces es más fácil para el lector seguir el código fuente.