Pensar en C++ (Volumen 1) - Grupo ARCO

Pensar en C++ (Volumen 1) - Grupo ARCO Pensar en C++ (Volumen 1) - Grupo ARCO

arco.esi.uclm.es
from arco.esi.uclm.es More from this publisher
13.01.2015 Views

✐ ✐ ✐ “Volumen1” — 2012/1/12 — 13:52 — page 320 — #358 ✐ Capítulo 11. Las referencias y el constructor de copia Objetos temporales En la línea 15 se empieza la llamada a f(h), y esta vez ignora el valor de retorno. Puede ver que se invoca el constructor de copia en la línea 16, igual que antes, para pasar el argumento. Y también, igual que antes, en la línea 21 se llama al constructor de copia para el valor de retorno. Pero el constructor de copia necesita una dirección para utilizar como destino (es decir, para trabajar con el puntero this). ¿De dónde procede esta dirección Esto prueba que el compilador puede crear un objeto temporal cuando lo necesita para evaluar adecuadamente una expresión. En este caso, crea uno que ni siquiera se le ve actuar como destino para el valor ignorado retornado por f(). El tiempo de vida de este objeto temporal es tan corto como sea posible para que el programa no se llene de objetos temporales esperando a ser destruidos, lo cual provocaría la utilización ineficaz de recursos valiosos. En algunos casos, el objeto temporal podría pasarse inmediatamente a otra función, pero en este caso no se necesita después de la llamada a la función, así que en cuanto la función termina, llamando al destructor del objeto local (líneas 23 y 24), el objeto temporal también se destruye (líneas 25 y 26). Finalmente, de la línea 28 a la línea 31, se destruye el objeto h2, seguido de h y el contador de objetos vuelve a cero. 11.3.3. El constructor de copia por defecto Como el constructor de copia implementa el paso y retorno por valor, es importante que el compilador cree uno en el caso de estructuras simples (de hecho, es lo mismo que hace C). Sin embargo todo lo que se ha visto es el comportamiento por defecto: una copia bit a bit. Cuando se utilizan tipos más complejos, el compilador de C++ creará un constructor de copia automáticamente si no se implementa explícitamente. De nuevo, una copia bit a bit no tiene sentido, porque no tiene porqué ser el comportamiento que se necesita. He aquí un ejemplo para mostrar el comportamiento más inteligente del compilador. Suponga que crea una nueva clase compuesta por objetos de varias clases diferentes. A esto se le denomina composición, y es una de las formas en las que se pueden hacer nuevas clases a partir de las ya existentes. Ahora desempeñe el papel de un novato que trata de resolver un problema rápidamente creando una nueva clase de esta manera. No sabe nada sobre los constructores de copia, así que no lo implementa. El ejemplo muestra lo que el compilador hace cuando crea un constructor de copia por defecto para su nueva clase: //: C11:DefaultCopyConstructor.cpp // Automatic creation of the copy-constructor #include #include using namespace std; class WithCC { // With copy-constructor public: // Explicit default constructor required: WithCC() {} WithCC(const WithCC&) { cout

✐ ✐ ✐ “Volumen1” — 2012/1/12 — 13:52 — page 321 — #359 ✐ 11.3. El constructor de copia }; class WoCC { // Without copy-constructor string id; public: WoCC(const string& ident = "") : id(ident) {} void print(const string& msg = "") const { if(msg.size() != 0) cout

✐<br />

✐<br />

✐<br />

“Volum<strong>en</strong>1” — 2012/1/12 — 13:52 — page 320 — #358<br />

✐<br />

Capítulo 11. Las refer<strong>en</strong>cias y el constructor de copia<br />

Objetos temporales<br />

En la línea 15 se empieza la llamada a f(h), y esta vez ignora el valor de retorno.<br />

Puede ver que se invoca el constructor de copia <strong>en</strong> la línea 16, igual que antes, para<br />

pasar el argum<strong>en</strong>to. Y también, igual que antes, <strong>en</strong> la línea 21 se llama al constructor<br />

de copia para el valor de retorno. Pero el constructor de copia necesita una dirección<br />

para utilizar como destino (es decir, para trabajar con el puntero this). ¿De dónde<br />

procede esta dirección<br />

Esto prueba que el compilador puede crear un objeto temporal cuando lo necesita<br />

para evaluar adecuadam<strong>en</strong>te una expresión. En este caso, crea uno que ni siquiera<br />

se le ve actuar como destino para el valor ignorado retornado por f(). El tiempo<br />

de vida de este objeto temporal es tan corto como sea posible para que el programa<br />

no se ll<strong>en</strong>e de objetos temporales esperando a ser destruidos, lo cual provocaría la<br />

utilización ineficaz de recursos valiosos. En algunos casos, el objeto temporal podría<br />

pasarse inmediatam<strong>en</strong>te a otra función, pero <strong>en</strong> este caso no se necesita después de<br />

la llamada a la función, así que <strong>en</strong> cuanto la función termina, llamando al destructor<br />

del objeto local (líneas 23 y 24), el objeto temporal también se destruye (líneas 25 y<br />

26).<br />

Finalm<strong>en</strong>te, de la línea 28 a la línea 31, se destruye el objeto h2, seguido de h y el<br />

contador de objetos vuelve a cero.<br />

11.3.3. El constructor de copia por defecto<br />

Como el constructor de copia implem<strong>en</strong>ta el paso y retorno por valor, es importante<br />

que el compilador cree uno <strong>en</strong> el caso de estructuras simples (de hecho, es lo<br />

mismo que hace C). Sin embargo todo lo que se ha visto es el comportami<strong>en</strong>to por<br />

defecto: una copia bit a bit.<br />

Cuando se utilizan tipos más complejos, el compilador de <strong>C++</strong> creará un constructor<br />

de copia automáticam<strong>en</strong>te si no se implem<strong>en</strong>ta explícitam<strong>en</strong>te. De nuevo,<br />

una copia bit a bit no ti<strong>en</strong>e s<strong>en</strong>tido, porque no ti<strong>en</strong>e porqué ser el comportami<strong>en</strong>to<br />

que se necesita.<br />

He aquí un ejemplo para mostrar el comportami<strong>en</strong>to más intelig<strong>en</strong>te del compilador.<br />

Suponga que crea una nueva clase compuesta por objetos de varias clases<br />

difer<strong>en</strong>tes. A esto se le d<strong>en</strong>omina composición, y es una de las formas <strong>en</strong> las que se<br />

pued<strong>en</strong> hacer nuevas clases a partir de las ya exist<strong>en</strong>tes. Ahora desempeñe el papel<br />

de un novato que trata de resolver un problema rápidam<strong>en</strong>te creando una nueva<br />

clase de esta manera. No sabe nada sobre los constructores de copia, así que no lo implem<strong>en</strong>ta.<br />

El ejemplo muestra lo que el compilador hace cuando crea un constructor<br />

de copia por defecto para su nueva clase:<br />

//: C11:DefaultCopyConstructor.cpp<br />

// Automatic creation of the copy-constructor<br />

#include <br />

#include <br />

using namespace std;<br />

class WithCC { // With copy-constructor<br />

public:<br />

// Explicit default constructor required:<br />

WithCC() {}<br />

WithCC(const WithCC&) {<br />

cout

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!