13.01.2015 Views

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

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

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

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

✐<br />

✐<br />

✐<br />

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

✐<br />

13.3. new y delete para vectores<br />

re. Frecu<strong>en</strong>tem<strong>en</strong>te la razón para cambiar el asignador es la efici<strong>en</strong>cia; puede que<br />

se necesite crear y destruir tantos objetos de la misma clase que lo haga ineficaz <strong>en</strong><br />

términos de velocidad: un cuello de botella. En <strong>C++</strong> es posible sobrecargar new y d-<br />

elete para implem<strong>en</strong>tar un esquema particular más adecuado que permita manejar<br />

situaciones como ésta.<br />

Otra cuestión es la fragm<strong>en</strong>tación del montículo. Cuando los objetos ti<strong>en</strong><strong>en</strong> tamaños<br />

difer<strong>en</strong>tes es posible llegar a dividir de tal modo el área de memoria libre que<br />

se vuelva inútil. Es decir, el espacio puede estar disponible, pero debido al nivel de<br />

fragm<strong>en</strong>tación alcanzado, no exista ningún bloque del tamaño requerido. Es posible<br />

asegurarse de que esto no llegue a ocurrir mediante la creación de un asignador para<br />

una clase específica.<br />

En los sistemas de tiempo real y <strong>en</strong> los sistemas integrados, suele ser necesario<br />

que los programas funcion<strong>en</strong> por largo tiempo con recursos muy limitados. Tales<br />

sistemas pued<strong>en</strong> incluso requerir que cada asignación tome siempre la misma cantidad<br />

de tiempo, y que no esté permitida la fragm<strong>en</strong>tación ni el agotami<strong>en</strong>to <strong>en</strong> el área<br />

dinámica. La solución a este problema consiste <strong>en</strong> utilizar un asignador «personalizado»;<br />

de otro modo, los programadores evitarían usar new y delete es estos casos<br />

y desperdiciarían un recurso muy valioso de <strong>C++</strong>.<br />

A la hora de sobrecargar operator new() y operator delete() es importante<br />

t<strong>en</strong>er <strong>en</strong> cu<strong>en</strong>ta que lo único que se está cambiando es la forma <strong>en</strong> que se realiza<br />

la asignación del espacio. El compilador llamará a la nueva versión de new <strong>en</strong> lugar<br />

de al original, para asignar espacio, llamando después al constructor que actuará sobre<br />

él. Así que, aunque el compilador convierte una expresión new <strong>en</strong> código para<br />

asignar el espacio y para llamar al constructor, todo lo que se puede cambiar al sobrecargar<br />

new es la parte correspondi<strong>en</strong>te a la asignación. delete ti<strong>en</strong>e una limitación<br />

similar.<br />

Cuando se sobrecarga operator new(), se está reemplazando también el modo<br />

de tratar los posibles fallos <strong>en</strong> la asignación de la memoria. Se debe decidir qué<br />

acciones va a realizar <strong>en</strong> tal caso: devolver cero, un bucle de reint<strong>en</strong>to con llamada<br />

al new-handler, o lo que es más frecu<strong>en</strong>te, disparar una excepción bad_alloc (tema que<br />

se trata <strong>en</strong> el Volum<strong>en</strong> 2).<br />

La sobrecarga de new y delete es como la de cualquier otro operador. Existe la<br />

posibilidad de elegir <strong>en</strong>tre sobrecarga global y sobrecarga para una clase determinada.<br />

Sobrecarga global de new y delete<br />

Este es el modo más drástico de abordar el asunto, resulta útil cuando el comportami<strong>en</strong>to<br />

de new y delete no es satisfactorio para la mayor parte del sistema. Al<br />

sobrecargar la versión global, quedan inaccesibles las originales, y ya no es posible<br />

llamarlas desde d<strong>en</strong>tro de las funciones sobrecargadas.<br />

El new sobrecargado debe tomar un argum<strong>en</strong>to del tipo size_t (el estándar de C)<br />

para tamaños. Este argum<strong>en</strong>to es g<strong>en</strong>erado y pasado por el compilador, y se refiere al<br />

tamaño del objeto para el que ahora t<strong>en</strong>emos la responsabilidad de la asignación de<br />

memoria. Debe devolver un puntero a un bloque de ese tamaño, (o mayor, si hubiera<br />

motivos para hacerlo así), o cero <strong>en</strong> el caso de no se <strong>en</strong>contrara un bloque adecuado.<br />

Si eso sucede, no se producirá la llamada al constructor. Por supuesto, hay que hacer<br />

algo más informativo que sólo devolver cero, por ejemplo llamar al «new-handler»<br />

o disparar una excepción, para indicar que hubo un problema.<br />

El valor de retorno de operator new() es void*, no un puntero a un tipo particular.<br />

Lo que hace es obt<strong>en</strong>er un bloque de memoria, no un objeto definido, no hasta<br />

391<br />

✐<br />

✐<br />

✐<br />

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

Saved successfully!

Ooh no, something went wrong!