jueves, 8 de mayo de 2008

COMENTARIOS ESPECIFICOS


La matriz m1 es de naturaleza estática, ya que es global al fichero . La especificación de tipo de almacenamiento está implícita en la propia situación de la declaración en L.2, fuera de cualquier función.
La matriz m2 es estática por la utilización explícita del especificador static en L.8; el compilador se encarga de reservar espacio adecuado en el segmento de datos. La matriz conserva sus valores entre posibles invocaciones sucesivas a func.
m3 es una alternativa a la anterior. Se declara un puntero-a-int de naturaleza estática; este puntero es almacenado en el segmento, por lo que conservará su valor entre llamadas sucesivas a la función. A su vez este puntero señala a un espacio en el montón; espacio que ha sido reservado mediante el operador new, así que los valores almacenados serán también persistentes.
Nota: el ejemplo es méramente didáctico y no sería operativo. Existe una diferencia adicional importante entre las opciones L.8/L.9. En L.8 el espacio es reservado una sola vez por el compilador, y es iniciado una sola vez por el módulo de inicio. En cambio, la opción L.9 reservaría un nuevo espacio con cada sucesiva invocación a la función.

La matriz m4 es de naturaleza automática, se creará en la pila y será iniciada y destruida con cada invocación a func.
Dejando aparte la declaración estática en sus dos versiones, implícita (L.2) o explícita (L.8), para crear una matriz en el montón existen dos procedimientos, según el tipo de funciones utilizadas. El que denominaremos "clásico", que utiliza las funciones "modernas" que utilizaría los operadores new / delete respectivamente. En ambos casos la referencia al elemento creado se realiza mediante un puntero.

Para crear la matriz int
m1[10] en el montón según el sistema moderno, se utilizaría la expresión:
int* m1;m1 = new int[10];
La consecuencia de estas sentencias es que se declara un puntero-a-int denominado m1; esta variable se crea en la pila (es automática), y a este Lvalue se le asigna el valor devuelto por el operador "new " que es la dirección de un espacio de memoria reservado en el montón.

El resultado sería la situación de memoria esquematizada en la figura 3, con la diferencia respecto al caso de las matrices estáticas anteriores (L.2 y L.8
), de que ahora existen dos objetos: un puntero en la pila, y un espacio anónimo en el montón (accesible mediante el puntero). El inconveniente es que hay que acordarse de desasignar la zona de memoria del montón cuando resulte innecesaria [2]. Esto se realizaría con la sentencia:
delete[] m1;

Procedimiento para crear la misma matriz según el sistema clásico:
int* m1 = (int*) calloc(10, sizeof(int));
También en este caso m1 se declara como puntero-a-int, y se le asigna el valor devuelto por la función calloc; el resultado sería idéntico al anterior. Observe que en este caso se necesita un modelado "casting" antes de la asignación a m1, porque el valor devuelto por calloc es un puntero-a-void, y no se puede asignar directamente a un puntero-a-int. La versión actualizada del modelado sería:
int* m1 = static_cast( calloc(10, sizeof(int)) );
§4.2.1 Como se comprueba a continuación, aunque se haya definido en términos de puntero-a-int, nada impide considerar a m1 como una auténtica matriz a todos los efectos (puede aplicársele la notación de subíndices):
#include int main() { // ============= int* m = new int[5]; for (int i = 0; i <5>No obstante lo anterior, considere los sorpresivos resultados del siguiente programa que crea tres matrices, m1, m2 y m3 utilizando los tres métodos señalados anteriormente:
#include using namespace std;void main() { // ============= int m1[5]; int* m2 = new int[5]; int* m3 = static_cast( calloc(5, sizeof(int)) ); cout << x =" 5;m2">
Inicio.
[1] Funciones de la Librería Estándar C++ que son en realidad herencia del C clásico.
[2] Cuando se reserva espacio en el montón mediante sentencias como new o calloc, junto con el propio espacio, el compilador incluye alguna información adicional, como el tamaño del área reservada. Por esta razón puede desasignar todo el espacio con una sola instrucción, delete o free, indicando solo el punto de comienzo del área a liberar.
Inicio

La matriz m1 es de naturaleza estática, ya que es global al fichero . La especificación de tipo de almacenamiento está implícita en la propia situación de la declaración en L.2, fuera de cualquier función.
La matriz m2 es estática por la utilización explícita del especificador static en L.8; el compilador se encarga de reservar espacio adecuado en el segmento de datos. La matriz conserva sus valores entre posibles invocaciones sucesivas a func.
m3 es una alternativa a la anterior. Se declara un puntero-a-int de naturaleza estática; este puntero es almacenado en el segmento, por lo que conservará su valor entre llamadas sucesivas a la función. A su vez este puntero señala a un espacio en el montón; espacio que ha sido reservado mediante el operador new, así que los valores almacenados serán también persistentes.
Nota: el ejemplo es méramente didáctico y no sería operativo. Existe una diferencia adicional importante entre las opciones L.8/L.9. En L.8 el espacio es reservado una sola vez por el compilador, y es iniciado una sola vez por el módulo de inicio. En cambio, la opción L.9 reservaría un nuevo espacio con cada sucesiva invocación a la función.
La matriz m4 es de naturaleza automática, se creará en la pila y será iniciada y destruida con cada invocación a func.
Dejando aparte la declaración estática en sus dos versiones, implícita (L.2) o explícita (L.8), para crear una matriz en el montón existen dos procedimientos, según el tipo de funciones utilizadas. El que denominaremos "clásico", que utiliza las funciones calloc / free [1] y el "moderno" que utilizaría los operadores new / delete respectivamente. En ambos casos la referencia al elemento creado se realiza mediante un puntero.
Para crear la matriz int m1[10] en el montón según el sistema moderno, se utilizaría la expresión:
int* m1;m1 = new int[10];
La consecuencia de estas sentencias es que se declara un puntero-a-int denominado m1; esta variable se crea en la pila (es automática), y a este Lvalue se le asigna el valor devuelto por el operador new que es la dirección de un espacio de memoria reservado en el montón.
El resultado sería la situación de memoria esquematizada en la figura 3, con la diferencia respecto al caso de las matrices estáticas anteriores (L.2 y L.8 ), de que ahora existen dos objetos: un puntero en la pila, y un espacio anónimo en el montón (accesible mediante el puntero). El inconveniente es que hay que acordarse de desasignar la zona de memoria del montón cuando resulte innecesaria [2]. Esto se realizaría con la sentencia:
delete[] m1;
Procedimiento para crear la misma matriz según el sistema clásico:
int* m1 = (int*) calloc(10, sizeof(int));
También en este caso m1 se declara como puntero-a-int, y se le asigna el valor devuelto por la función calloc; el resultado sería idéntico al anterior. Observe que en este caso se necesita un modelado ("casting"
4.9.9) antes de la asignación a m1, porque el valor devuelto por calloc es un puntero-a-void, y no se puede asignar directamente a un puntero-a-int. La versión actualizada del modelado sería:
int* m1 = static_cast( calloc(10, sizeof(int)) );
Como se comprueba a continuación, aunque se haya definido en términos de puntero-a-int, nada impide considerar a m1 como una auténtica matriz a todos los efectos (puede aplicársele la notación de subíndices):
#include int main() { // ============= int* m = new int[5]; for (int i = 0; i <5>
No obstante lo anterior, considere los sorpresivos resultados del siguiente programa que crea tres matrices, m1, m2 y m3 utilizando los tres métodos señalados anteriormente:
#include using namespace std;void main() { // ============= int m1[5]; int* m2 = new int[5]; int* m3 = static_cast( calloc(5, sizeof(int)) ); cout << x =" 5;m2">
Inicio.
[1] Funciones de la Librería Estándar C++ que son en realidad herencia del C clásico.
[2] Cuando se reserva espacio en el montón mediante sentencias como new o calloc, junto con el propio espacio, el compilador incluye alguna información adicional, como el tamaño del área reservada. Por esta razón puede desasignar todo el espacio con una sola instrucción, delete o free, indicando solo el punto de comienzo del área a liberar.