Classi di archiviazione
Una classe di archiviazione nel contesto delle dichiarazioni di variabili C++ è un identificatore di tipo che regola la durata, il collegamento e la posizione di memoria degli oggetti. Un oggetto specificato può avere una sola classe di archiviazione. Le variabili definite all'interno di un blocco hanno una risorsa di archiviazione automatica, a meno che non diversamente specificato usando gli extern
identificatori , static
o thread_local
. Gli oggetti automatici e le variabili non hanno alcun collegamento; non sono visibili al codice all'esterno del blocco. La memoria viene allocata automaticamente quando l'esecuzione entra nel blocco e viene deallocata quando il blocco viene chiuso.
Note
La
mutable
parola chiave può essere considerata un identificatore di classe di archiviazione. Tuttavia, è disponibile solo nell'elenco dei membri di una definizione di classe.Visual Studio 2010 e versioni successive: la
auto
parola chiave non è più un identificatore di classe di archiviazione C++ e laregister
parola chiave è deprecata. Visual Studio 2017 versione 15.7 e successive: (disponibile in/std:c++17
modalità e versioni successive): laregister
parola chiave viene rimossa dal linguaggio C++. L'uso causa un messaggio di diagnostica:// c5033.cpp // compile by using: cl /c /std:c++17 c5033.cpp register int value; // warning C5033: 'register' is no longer a supported storage class
static
La static
parola chiave può essere usata per dichiarare variabili e funzioni nell'ambito globale, nell'ambito dello spazio dei nomi e nell'ambito della classe. Le variabili statiche possono essere dichiarate anche in ambito locale.
La durata statica significa che l'oggetto o la variabile viene allocata all'avvio del programma e viene rilasciata alla chiusura del programma. Il collegamento esterno indica che il nome della variabile è visibile dall'esterno del file in cui viene dichiarata la variabile. Viceversa, il collegamento interno indica che il nome non è visibile all'esterno del file in cui viene dichiarata la variabile. Per impostazione predefinita, un oggetto o una variabile definiti nello spazio dei nomi globale presentano una durata e un collegamento esterno statici. La static
parola chiave può essere usata nelle situazioni seguenti.
Quando si dichiara una variabile o una funzione nell'ambito del file (ambito globale e/o dello spazio dei nomi), la
static
parola chiave specifica che la variabile o la funzione ha un collegamento interno. Quando si dichiara una variabile, questa ha una durata statica e il compilatore la inizializza con il valore 0 a meno che non venga specificato un altro valore.Quando si dichiara una variabile in una funzione, la
static
parola chiave specifica che la variabile mantiene lo stato tra le chiamate a tale funzione.Quando si dichiara un membro dati in una dichiarazione di classe, la
static
parola chiave specifica che una copia del membro viene condivisa da tutte le istanze della classe . Unstatic
membro dati deve essere definito nell'ambito del file. Un membro dati integrale dichiarato comeconst static
può avere un inizializzatore.Quando si dichiara una funzione membro in una dichiarazione di classe, la
static
parola chiave specifica che la funzione è condivisa da tutte le istanze della classe . Unastatic
funzione membro non può accedere a un membro dell'istanza perché la funzione non ha un puntatore implicitothis
. Per accedere a un membro dell'istanza, dichiarare la funzione con un parametro che rappresenta un puntatore o un riferimento all'istanza.Non è possibile dichiarare i membri di un
union
oggetto comestatic
. Tuttavia, un anonimounion
dichiarato a livello globale deve essere dichiaratostatic
in modo esplicito.
In questo esempio viene illustrato come una variabile dichiarata static
in una funzione mantenga lo stato tra le chiamate a tale funzione.
// static1.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
void showstat( int curr ) {
static int nStatic; // Value of nStatic is retained
// between each function call
nStatic += curr;
cout << "nStatic is " << nStatic << endl;
}
int main() {
for ( int i = 0; i < 5; i++ )
showstat( i );
}
nStatic is 0
nStatic is 1
nStatic is 3
nStatic is 6
nStatic is 10
In questo esempio viene illustrato l'uso di static
in una classe .
// static2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class CMyClass {
public:
static int m_i;
};
int CMyClass::m_i = 0;
CMyClass myObject1;
CMyClass myObject2;
int main() {
cout << myObject1.m_i << endl;
cout << myObject2.m_i << endl;
myObject1.m_i = 1;
cout << myObject1.m_i << endl;
cout << myObject2.m_i << endl;
myObject2.m_i = 2;
cout << myObject1.m_i << endl;
cout << myObject2.m_i << endl;
CMyClass::m_i = 3;
cout << myObject1.m_i << endl;
cout << myObject2.m_i << endl;
}
0
0
1
1
2
2
3
3
Nell'esempio seguente viene illustrata una variabile locale dichiarata static
in una funzione membro. La static
variabile è disponibile per l'intero programma. Tutte le istanze del tipo condividono la stessa copia della static
variabile.
// static3.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
struct C {
void Test(int value) {
static int var = 0;
if (var == value)
cout << "var == value" << endl;
else
cout << "var != value" << endl;
var = value;
}
};
int main() {
C c1;
C c2;
c1.Test(100);
c2.Test(100);
}
var != value
var == value
A partire da C++11, l'inizializzazione di una static
variabile locale è garantita come thread-safe. Questa funzionalità è talvolta denominata statici magic. In un'applicazione con multithreading, tuttavia, tutte le assegnazioni successive devono essere sincronizzate. La funzionalità di inizializzazione statica thread-safe può essere disabilitata usando il /Zc:threadSafeInit-
flag per evitare di assumere una dipendenza da CRT.
extern
Oggetti e variabili dichiarati come extern
dichiarano un oggetto definito in un'altra unità di conversione o in un ambito di inclusione come collegamento esterno. Per altre informazioni, vedere extern
Unità di traduzione e collegamento.
thread_local
(C++11)
Una variabile dichiarata con l'identificatore thread_local
è accessibile solo nel thread in cui viene creato. La variabile viene creata al momento della creazione del thread e viene eliminata definitivamente quando il thread viene eliminato definitivamente. Ogni thread ha la propria copia della variabile. In Windows thread_local
è funzionalmente equivalente all'attributo specifico __declspec( thread )
di Microsoft.
thread_local float f = 42.0; // Global namespace. Not implicitly static.
struct S // cannot be applied to type definition
{
thread_local int i; // Illegal. The member must be static.
thread_local static char buf[10]; // OK
};
void DoSomething()
{
// Apply thread_local to a local variable.
// Implicitly "thread_local static S my_struct".
thread_local S my_struct;
}
Aspetti da notare sull'identificatore thread_local
:
Le variabili thread-local in DLL inizializzate dinamicamente potrebbero non essere inizializzate correttamente in tutti i thread chiamanti. Per ulteriori informazioni, vedere
thread
.L'identificatore
thread_local
può essere combinato constatic
oextern
.È possibile applicare
thread_local
solo alle dichiarazioni e alle definizioni dei dati.thread_local
Non può essere usato nelle dichiarazioni o nelle definizioni di funzione.È possibile specificare
thread_local
solo sugli elementi di dati con durata di archiviazione statica, che include oggetti dati globali (estatic
extern
), oggetti statici locali e membri dati statici delle classi. Qualsiasi variabile locale dichiaratathread_local
è implicitamente statica se non viene fornita alcuna altra classe di archiviazione; in altre parole, l'ambitothread_local
del blocco equivale athread_local static
.È necessario specificare
thread_local
per la dichiarazione e la definizione di un oggetto locale di thread, indipendentemente dal fatto che la definizione e la dichiarazione si verificano nello stesso file o in file separati.Non è consigliabile usare
thread_local
le variabili constd::launch::async
. Per altre informazioni, vedere<future>
Funzioni.
In Windows thread_local
, è funzionalmente equivalente a __declspec(thread)
, ad eccezione del fatto che *__declspec(thread)
* può essere applicato a una definizione di tipo ed è valido nel codice C. Quando possibile, usare thread_local
perché fa parte dello standard C++ ed è quindi più portabile.
register
Visual Studio 2017 versione 15.3 e successive (disponibile in /std:c++17
modalità e versioni successive): la register
parola chiave non è più una classe di archiviazione supportata. L'uso di genera una diagnostica. La parola chiave è ancora riservata nello standard per un uso futuro.
register int val; // warning C5033: 'register' is no longer a supported storage class
Esempio: inizializzazione automatica e statica
Ogni volta che il flusso di controllo raggiunge la propria definizione, vengono inizializzati un oggetto o una variabile locali automatici. La prima volta che il flusso di controllo raggiunge la relativa definizione, vengono inizializzati un oggetto o una variabile statici.
Si consideri l'esempio seguente, nel quale si definisce una classe che registra l'inizializzazione e l'eliminazione di oggetti e, in seguito, definisce tre oggetti, I1
, I2
e I3
:
// initialization_of_objects.cpp
// compile with: /EHsc
#include <iostream>
#include <string.h>
using namespace std;
// Define a class that logs initializations and destructions.
class InitDemo {
public:
InitDemo( const char *szWhat );
~InitDemo();
private:
char *szObjName;
size_t sizeofObjName;
};
// Constructor for class InitDemo
InitDemo::InitDemo( const char *szWhat ) :
szObjName(NULL), sizeofObjName(0) {
if ( szWhat != 0 && strlen( szWhat ) > 0 ) {
// Allocate storage for szObjName, then copy
// initializer szWhat into szObjName, using
// secured CRT functions.
sizeofObjName = strlen( szWhat ) + 1;
szObjName = new char[ sizeofObjName ];
strcpy_s( szObjName, sizeofObjName, szWhat );
cout << "Initializing: " << szObjName << "\n";
}
else {
szObjName = 0;
}
}
// Destructor for InitDemo
InitDemo::~InitDemo() {
if( szObjName != 0 ) {
cout << "Destroying: " << szObjName << "\n";
delete szObjName;
}
}
// Enter main function
int main() {
InitDemo I1( "Auto I1" ); {
cout << "In block.\n";
InitDemo I2( "Auto I2" );
static InitDemo I3( "Static I3" );
}
cout << "Exited block.\n";
}
Initializing: Auto I1
In block.
Initializing: Auto I2
Initializing: Static I3
Destroying: Auto I2
Exited block.
Destroying: Auto I1
Destroying: Static I3
In questo esempio viene illustrato come e quando gli oggetti I1
, I2
e I3
vengono inizializzati e quando vengono eliminati definitivamente.
Ci sono diversi punti da notare sul programma:
Prima di tutto,
I1
eI2
vengono eliminati automaticamente quando il flusso di controllo esce dal blocco in cui sono definiti.In secondo luogo, in C++, non è necessario dichiarare oggetti o variabili all'inizio di un blocco. Questi oggetti, inoltre, vengono inizializzati solo quando il flusso di controllo raggiunge le relative definizioni. (
I2
eI3
sono esempi di tali definizioni. L'output mostra esattamente quando vengono inizializzati.Infine, le variabili locali statiche, ad
I3
esempio, mantengono i valori durante l'esecuzione del programma, ma vengono eliminate definitivamente al termine del programma.
Vedi anche
Commenti e suggerimenti
https://aka.ms/ContentUserFeedback.
Presto disponibile: Nel corso del 2024 verranno gradualmente disattivati i problemi di GitHub come meccanismo di feedback per il contenuto e ciò verrà sostituito con un nuovo sistema di feedback. Per altre informazioni, vedereInvia e visualizza il feedback per