2012-01-14 4 views
8

Questo mi ha turbato per un po '. Va al cuore della mia (mancanza di) comprensione della differenza tra allocazione di memoria statica e dinamica. Il seguente array è un ordinario array statico, che dovrebbe significare che la memoria è allocata durante il tempo di compilazione, corretto? Tuttavia, l'ho impostato in modo che l'utente inserisca la dimensione dell'array in fase di runtime.L'array è statico, ma la dimensione dell'array non è nota fino al runtime. Com'è possibile?

#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; 
} 

Nota che non ci sono new o delete operatori del programma. Funziona perfettamente con Xcode 4.2 (compilatore Clang predefinito) e con il server UNIX della mia scuola (GCC 4.4.5). Come fa il compilatore a sapere quanta memoria allocare per arr quando la matrice viene creata in fase di compilazione? È solo un colpo di fortuna del mio compilatore, un codice pericoloso che potrebbe corrompere altri ricordi, o è legittimo?

+1

Questo utilizza una funzione chiamata _variable lunghezza arrays_, che ha debuttato nel C99. –

+3

Prova a compilarlo con 'g ++ -Wall -Wextra -pedantic -std = C++ 98' –

risposta

8

Questa è un'estensione non standard dei compilatori C++. Si noti che in C, a differenza di C++, questo è ufficialmente supportato (vale a dire il comportamento con mandato standard) dal C99. In C++, non è supportato perché esiste già una soluzione al problema: utilizzare std::vector anziché l'array.

Non è tuttavia possibile che l'array sia non utilizzando l'allocazione di memoria statica (né l'allocazione di memoria dinamica), ma l'allocazione di memoria automatica. Le variabili automatiche vengono automaticamente deallocate alla fine della funzione (l'area di memoria in cui sono allocate è nota come stack, poiché le allocazioni e le allocazioni su di essa hanno semantica dello stack). Per fare in modo che l'array usi l'allocazione della memoria statica, è necessario inserire static di fronte alla definizione (si noti che le variabili in ambito globale o namespace utilizzano sempre l'allocazione della memoria statica, comunque). Tuttavia, se si rende la variabile statica, si scoprirà che il compilatore non consente più di utilizzare una dimensione di matrice non costante.

Nota che std::vector memorizza i propri dati con allocazioni di memoria dinamica. Per questo motivo, è anche possibile utilizzare una dimensione non costante anche per statici std::vector s.

+0

Il motivo principale per cui non è consentito non è che ci sia l'alternativa del vettore. Ci sono ragioni più profonde, come il fatto che la dimensione di un array è parte del tipo e deve essere nota al momento della compilazione. –

+0

@ DavidRodríguez-dribeas: Avrebbero potuto fare eccezioni a quelle regole, proprio come gli array di lunghezza variabile C richiedevano eccezioni alle regole di C. – celtschk

0

È un Variable Length Array (supportato solo in C99 e non in C++). Viene assegnato nello stack in fase di runtime.

+0

E 'anche C++ valido? IIRC il Visual Studio ha avuto alcuni errori su questo. – stativ

+0

stativ è corretto; questo non è C++. –

+0

No, non è l'allocazione dinamica della memoria. È l'allocazione automatica della memoria. @stativ: No, non è valido C++ (sarebbe valido C se non circondato da codice specifico C++, comunque). Per C++, è un'estensione non standard di alcuni compilatori. – celtschk

1

Il codice generato alloca i byte arraySize nello stack in fase di esecuzione. Una volta che la funzione ritorna, lo stack si svolge, incluso "restituire" i byte che sono stati allocati su di esso per l'array.

L'utilizzo di new e delete è per l'allocazione dello spazio sull'heap. La durata della memoria allocata nell'heap è indipendente da qualsiasi funzione o ambito del metodo: se si alloca spazio su di essa in una funzione e la funzione restituisce, la memoria viene comunque allocata e valida.

4

Per una matrice (o qualsiasi oggetto) dichiarata all'interno di una funzione, la memoria viene allocata all'ingresso della funzione (in genere sullo stack) e rilasciata quando la funzione restituisce. Il fatto che la funzione sia in questo caso main non influisce su questo.

Questo:

cin >> arraySize; 
int arr[arraySize]; 

è una "matrice di lunghezza variabile" (VLA). Il fatto è che C++ non supporta VLA. C fa, a partire dallo standard ISO C del 1999 (C99), ma non è una caratteristica adottata dal C++.

Il compilatore supporta VLA in C++ come estensione. Usarli rende il tuo codice non portatile.

(Un problema con VLA è che non esiste un meccanismo per rilevare un errore di allocazione, se arraySize è troppo grande, il comportamento del programma non è definito).

Per gcc, la compilazione con -pedantic produrrà un avvertimento:

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