Pensar en C++ (Volumen 1) - Grupo ARCO
Pensar en C++ (Volumen 1) - Grupo ARCO
Pensar en C++ (Volumen 1) - Grupo ARCO
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 />
✐