2012-01-14 7 views
8

Esto me ha estado preocupando por un tiempo. Va al corazón de mi (falta de) comprensión de la diferencia entre la asignación de memoria estática y dinámica. La siguiente matriz es una matriz estática ordinaria, que debería significar que la memoria se asigna durante el tiempo de compilación, ¿correcto? Sin embargo, lo configuré para que el usuario ingrese el tamaño de la matriz en tiempo de ejecución.La matriz es estática, pero el tamaño de la matriz no se conoce hasta el tiempo de ejecución. ¿Cómo es esto posible?

#include <iostream> 
using namespace std; 

int main() { 
    cout << "how many elements should the array hold? "; 
    int arraySize; 
    cin >> arraySize; 

    int arr[arraySize]; 

    for (int i = 0; i < arraySize; ++i) 
    arr[i] = i * 2; 

    return 0; 
} 

Tenga en cuenta que no hay new o delete operadores en este programa. Funciona bien en Xcode 4.2 (compilador predeterminado de Clang) y en el servidor UNIX de mi escuela (GCC 4.4.5). ¿Cómo sabe el compilador cuánta memoria asignar en arr cuando la matriz se crea en tiempo de compilación? ¿Es esto solo una casualidad de mi compilador, un código peligroso que podría dañar otra memoria, o es legítimo?

+1

Esto usa una función llamada de longitud _variable arrays_, que debutó en C99. –

+3

Intenta compilar con 'g ++ -Wall -Wextra -pedantic -std = C++ 98' –

Respuesta

8

Esta es una extensión no estándar de sus compiladores de C++. Tenga en cuenta que en C, a diferencia de C++, esto es oficialmente compatible (es decir, el comportamiento obligatorio estándar) desde C99. En C++, no es compatible porque ya hay una solución al problema: use std::vector en lugar de la matriz.

Sin embargo, no es que la matriz sea ni utilizando la asignación de memoria estática (ni la asignación de memoria dinámica), sino la asignación de memoria automática. Las variables automáticas se desasignan automáticamente al final de la función (el área de memoria donde se asignan se conoce como pila, porque las asignaciones y desasignaciones tienen semántica de pila). Para que la matriz utilice la asignación de memoria estática, debe poner static al frente de la definición (tenga en cuenta que las variables en el ámbito global o de espacio de nombres siempre usan la asignación de memoria estática). Sin embargo, si hace que la variable sea estática, encontrará que el compilador ya no permite usar un tamaño de matriz no constante.

Tenga en cuenta que std::vector almacena sus datos con asignaciones dinámicas de memoria. Por esa razón, también puede usar un tamaño no constante incluso para estáticas std::vector s.

+0

La razón principal de que no esté permitido no es que exista la alternativa de vector. Hay razones más profundas, como el hecho de que el tamaño de una matriz es parte del tipo y debe conocerse en tiempo de compilación. –

+0

@ DavidRodríguez-dribeas: Podrían haber hecho excepciones a esas reglas, al igual que las matrices de longitud variable C necesitaban excepciones a las reglas de C. – celtschk

0

Es un Variable Length Array (solo compatible con C99 y no con C++). Se asigna en la pila en tiempo de ejecución.

+0

¿Es esto incluso válido C++? IIRC el Visual Studio tuvo algunos errores sobre esto. – stativ

+0

stativ es correcto; esto no es C++. –

+0

No, no es una asignación de memoria dinámica. Es asignación de memoria automática. @stativ: No, no es válido C++ (sin embargo, sería válido C si no estuviera rodeado por un código específico de C++). Para C++, es una extensión no estándar de algunos compiladores. – celtschk

1

El código generado asigna bytes de tamaño de matriz en la pila en tiempo de ejecución. Una vez que la función retorna, la pila se desenrolla, incluyendo "devolver" los bytes asignados en ella para la matriz.

Utilizar new y delete es para asignar espacio en el montón. La duración de la memoria asignada en el montón es independiente de cualquier alcance de la función o método: si asigna espacio en una función y la función vuelve, la memoria sigue asignada y es válida.

4

Para una matriz (o cualquier objeto) declarada dentro de una función, la memoria se asigna al ingresar a la función (normalmente en la pila) y se desasigna cuando la función retorna. El hecho de que la función sea main en este caso no afecta eso.

Este:

cin >> arraySize; 
int arr[arraySize]; 

es una "matriz de longitud variable" (VLA). El caso es que C++ no admite VLA. C lo hace, comenzando con el estándar ISO C 1999 (C99), pero no es una característica que C++ haya adoptado.

Su compilador admite VLA en C++ como una extensión. Su uso hace que su código no sea portátil.

(Un problema con los VLA es que no hay ningún mecanismo para detectar una falla de asignación; si arraySize es demasiado grande, el comportamiento del programa no está definido).

para GCC, compilar con -pedantic producirá una advertencia:

warning: ISO C++ forbids variable length array ‘arr’ 
Cuestiones relacionadas