Ciò che segue ovviamente non è del tutto preciso. Prendilo con un granello di sale quando lo leggi :)
Bene, le tre cose a cui ti riferisci sono la durata di archiviazione automatica, statica e dinamica , che ha a che fare con la durata della vita degli oggetti e quando iniziano la vita.
Durata di conservazione automatica
Si utilizza la durata di archiviazione automatica per dati di breve durata e piccoli , necessari solo localmente all'interno di un blocco:
if(some condition) {
int a[3]; // array a has automatic storage duration
fill_it(a);
print_it(a);
}
La durata termina non appena usciamo dal blocco e inizia non appena viene definito l'oggetto. Sono il tipo di durata di archiviazione più semplice e sono molto più veloci rispetto alla durata di archiviazione dinamica particolare.
Durata di conservazione statica
Si utilizza la durata dell'archiviazione statica per variabili libere, a cui è possibile accedere in qualsiasi momento da qualsiasi codice, se il loro ambito consente tale utilizzo (ambito dello spazio dei nomi) e per le variabili locali che devono prolungare la loro durata attraverso l'uscita dal loro ambito (ambito locale), e per le variabili membro che devono essere condivise da tutti gli oggetti della loro classe (ambito delle classi). La loro vita dipende l'ambito cui si trovano. Essi possono avere portata namespace e ambito locale e ambito di classe . Ciò che è vero in entrambi è che, una volta iniziata la loro vita, la vita finisce alla fine del programma . Ecco due esempi:
// static storage duration. in global namespace scope
string globalA;
int main() {
foo();
foo();
}
void foo() {
// static storage duration. in local scope
static string localA;
localA += "ab"
cout << localA;
}
Il programma stampa ababab
, perché localA
non viene distrutto all'uscita del suo blocco. Si può dire che gli oggetti con ambito locale iniziano la vita quando il controllo raggiunge la loro definizione . Per localA
, succede quando viene inserito il corpo della funzione. Per gli oggetti nell'ambito dello spazio dei nomi, la durata inizia all'avvio del programma . Lo stesso vale per gli oggetti statici di ambito di classe:
class A {
static string classScopeA;
};
string A::classScopeA;
A a, b; &a.classScopeA == &b.classScopeA == &A::classScopeA;
Come vedi, classScopeA
non è legato a oggetti particolari della sua classe, ma alla classe stessa. L'indirizzo di tutti e tre i nomi sopra è lo stesso e tutti indicano lo stesso oggetto. Esistono regole speciali su quando e come inizializzare gli oggetti statici, ma non preoccupiamoci di questo ora. Questo si intende con il termine fiasco dell'ordine di inizializzazione statica .
Durata della memoria dinamica
L'ultima durata della memoria è dinamica. Lo usi se vuoi che gli oggetti vivano su un'altra isola e vuoi mettere dei puntatori attorno a quel riferimento. Li usi anche se i tuoi oggetti sono grandi e se vuoi creare matrici di dimensioni conosciute solo in fase di esecuzione . A causa di questa flessibilità, gli oggetti con durata di archiviazione dinamica sono complicati e lenti da gestire. Gli oggetti con tale durata dinamica iniziano la vita quando si verifica una nuova chiamata dell'operatore appropriata :
int main() {
// the object that s points to has dynamic storage
// duration
string *s = new string;
// pass a pointer pointing to the object around.
// the object itself isn't touched
foo(s);
delete s;
}
void foo(string *s) {
cout << s->size();
}
La sua durata termina solo quando si chiama Elimina per loro. Se lo dimentichi, quegli oggetti non finiscono mai la vita. E agli oggetti di classe che definiscono un costruttore dichiarato dall'utente non verranno chiamati i loro distruttori. Gli oggetti con durata di archiviazione dinamica richiedono la gestione manuale della loro durata e delle risorse di memoria associate. Esistono librerie per facilitarne l'uso. La garbage collection esplicita per oggetti particolari può essere stabilita utilizzando un puntatore intelligente:
int main() {
shared_ptr<string> s(new string);
foo(s);
}
void foo(shared_ptr<string> s) {
cout << s->size();
}
Non devi preoccuparti di chiamare delete: il ptr condiviso lo fa per te, se l'ultimo puntatore che fa riferimento all'oggetto non rientra nell'ambito. Lo stesso ptr condiviso ha una durata di memorizzazione automatica. Pertanto, la sua durata viene gestita automaticamente, consentendogli di verificare se deve eliminare l'oggetto puntato a dinamico nel suo distruttore. Per riferimento shared_ptr, consultare i documenti boost: http://www.boost.org/doc/libs/1_37_0/libs/smart_ptr/shared_ptr.htm