Attention! Your ePaper is waiting for publication!
By publishing your document, the content will be optimally indexed by Google via AI and sorted into the right category for over 500 million ePaper readers on YUMPU.
This will ensure high visibility and many readers!
✐ ✐ ✐ “Volum<strong>en</strong>1” — 2012/1/12 — 13:52 — page 146 — #184 ✐ Capítulo 4. Abstracción de Datos De modo que con new Tipo se obt<strong>en</strong>drá un puntero a un objeto de tipo Tipo, y con new int obt<strong>en</strong>drá un puntero a un int. Si quiere un nuevo array de unsigned char la expresión devolverá un puntero al primer elem<strong>en</strong>to de dicho array. El compilador verificará que se asigne lo que devuelve la expresión-new a una variable puntero del tipo adecuado. Por supuesto, es posible que al pedir memoria, la petición falle, por ejemplo, si no hay más memoria libre <strong>en</strong> el sistema. Como verá más adelante, <strong>C++</strong> cu<strong>en</strong>ta con mecanismos que <strong>en</strong>tran <strong>en</strong> juego cuando la operación de asignación de memoria no se puede satisfacer. Una vez que se ha obt<strong>en</strong>ido un nuevo espacio de almac<strong>en</strong>ami<strong>en</strong>to, los datos que estaban <strong>en</strong> el antiguo se deb<strong>en</strong> copiar al nuevo. Esto se hace, nuevam<strong>en</strong>te, <strong>en</strong> un bucle, utilizando la notación de índexado de arrays, copiando un byte <strong>en</strong> cada iteración del bucle. Una vez finalizada esta copia, ya no se necesitan los datos que están <strong>en</strong> el espacio de almac<strong>en</strong>ami<strong>en</strong>to original por lo que se pued<strong>en</strong> liberar de la memoria para que otras partes del programa puedan usarlo cuando lo necesit<strong>en</strong>. La palabra reservada delete es el complem<strong>en</strong>to de new y se debe utilizar sobre todas aquellas variables a las cuales se les haya asignado memoria con new. (Si se olvida de utilizar delete esa memoria queda in-utilizable. Si estas fugas de memoria (memory leak) son demasiado abundantes, la memoria disponible se acabará.) Existe una sintaxis especial cuando se libera un array. Es como si recordara al compilador que ese puntero no apunta sólo a un objeto, sino a un array de objetos; se deb<strong>en</strong> poner un par de corchetes delante del puntero que se quiere liberar: delete []myArray; Una vez liberado el antiguo espacio de almac<strong>en</strong>ami<strong>en</strong>to, se puede asignar el puntero del nuevo espacio de memoria al puntero storage, se actualiza quantity y con eso inflate() ha terminado su trabajo. En este punto es bu<strong>en</strong>o notar que el administrador de memoria del montículo> es bastante primitivo. Nos facilita trozos de memoria cuando se lo pedimos con new y los libera cuando invocamos a delete. Si un programa asigna y libera memoria muchas veces, terminaremos con un montículo fragm<strong>en</strong>tado, es decir un montículo <strong>en</strong> el que si bi<strong>en</strong> puede haber memoria libre utilizable, los trozos de memoria están divididos de tal modo que no exista un trozo que sea lo sufici<strong>en</strong>tem<strong>en</strong>te grande para las necesidades concretas <strong>en</strong> un mom<strong>en</strong>to dado. Lam<strong>en</strong>tablem<strong>en</strong>te no existe una capacidad inher<strong>en</strong>te del l<strong>en</strong>guaje para efectuar defragm<strong>en</strong>taciones del montículo. Un defragm<strong>en</strong>tador del montículo complica las cosas dado que ti<strong>en</strong>e que mover pedazos de memoria, y por lo tanto, hacer que los punteros dej<strong>en</strong> de apuntar a valores válidos. Algunos <strong>en</strong>tornos operativos vi<strong>en</strong><strong>en</strong> con este tipo de facilidades pero obligan al programador a utilizar manejadores de memoria especiales <strong>en</strong> lugar de punteros (estos manipuladores se pued<strong>en</strong> convertir temporalm<strong>en</strong>te <strong>en</strong> punteros una vez bloqueada la memoria para que el defragm<strong>en</strong>tador del montículo no la modifique). También podemos construir nosotros mismos uno de estos artilugios, aunque no es una tarea s<strong>en</strong>cilla. Cuando creamos una variable <strong>en</strong> la pila <strong>en</strong> tiempo de compilación, el mismo compilador es qui<strong>en</strong> se <strong>en</strong>carga de crearla y liberar la memoria ocupada por ella automáticam<strong>en</strong>te. Conoce exactam<strong>en</strong>te el tamaño y la duración de este tipo de variables dada por las reglas de ámbito. Sin embargo, <strong>en</strong> el caso de las variables almac<strong>en</strong>adas dinámicam<strong>en</strong>te, el compilador no poseerá información ni del tamaño requerido por las mismas, ni de su duración. Esto significa que el compilador no puede <strong>en</strong>cargarse de liberar automáticam<strong>en</strong>te la memoria ocupada por este tipo de variables y de aquí 146 ✐ ✐ ✐ ✐
✐ ✐ ✐ “Volum<strong>en</strong>1” — 2012/1/12 — 13:52 — page 147 — #185 ✐ 4.1. Una librería pequeña al estilo C que el responsable de esta tarea sea el programador (o sea usted). Para esto se debe utilizar delete, lo cual le indica al administrador del montículo que ese espacio de memoria puede ser utilizado por próximas llamadas a new. En nuestra librería de ejemplo, el lugar lógico para esta tarea es la función cleanup() dado que allí es dónde se deb<strong>en</strong> realizar todas las labores de finalización de uso del objeto. Para probar la librería se crean dos Cstash, uno que almac<strong>en</strong>e <strong>en</strong>teros y otro para cad<strong>en</strong>as de 80 caracteres: //: C04:CLibTest.cpp //{L} CLib // Test the C-like library #include "CLib.h" #include #include #include #include using namespace std; int main() { // Define variables at the beginning // of the block, as in C: CStash intStash, stringStash; int i; char* cp; ifstream in; string line; const int bufsize = 80; // Now remember to initialize the variables: initialize(&intStash, sizeof(int)); for(i = 0; i < 100; i++) add(&intStash, &i); for(i = 0; i < count(&intStash); i++) cout