Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Une classe de stockage dans le contexte des déclarations de variables C++ est un spécificateur de type qui régit la durée de vie, la liaison et l’emplacement de mémoire des objets. Un objet donné ne peut avoir qu'une seule classe de stockage. Les variables définies dans un bloc ont un stockage automatique, sauf indication contraire à l’aide des spécificateurs ou extern des staticthread_localspécificateurs. Les objets et variables automatiques n’ont aucune liaison ; ils ne sont pas visibles pour le code en dehors du bloc. La mémoire est allouée automatiquement lorsque l’exécution entre dans le bloc et qu’elle est dé-allouée lorsque le bloc est arrêté.
Notes
Le
mutablemot clé peut être considéré comme un spécificateur de classe de stockage. Toutefois, il est disponible uniquement dans la liste des membres d’une définition de classe.Visual Studio 2010 et versions ultérieures : le
automot clé n’est plus un spécificateur de classe de stockage C++ et leregistermot clé est déconseillé. Visual Studio 2017 version 15.7 et ultérieure : (disponible en/std:c++17mode et versions ultérieures) : leregistermot clé est supprimé du langage C++. Son utilisation provoque un message de diagnostic :// 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
Le static mot clé peut être utilisé pour déclarer des variables et des fonctions dans l’étendue globale, l’étendue de l’espace de noms et l’étendue de classe. Les variables statiques peuvent également être déclarées dans la portée locale.
La durée statique signifie que l'objet ou la variable est alloué au démarrage du programme et est libéré à la fin de l'exécution du programme. La liaison externe signifie que le nom de la variable est visible à partir de l’extérieur du fichier où la variable est déclarée. À l’inverse, la liaison interne signifie que le nom n’est pas visible en dehors du fichier où la variable est déclarée. Par défaut, un objet ou une variable défini dans l'espace de noms global a une durée statique et une liaison externe. Le static mot clé peut être utilisé dans les situations suivantes.
Lorsque vous déclarez une variable ou une fonction au niveau de l’étendue de fichier (étendue globale et/ou d’espace de noms), le
staticmot clé spécifie que la variable ou la fonction a une liaison interne. Lorsque vous déclarez une variable, la variable a une durée statique et le compilateur l'initialise à 0, sauf si vous spécifiez une autre valeur.Lorsque vous déclarez une variable dans une fonction, le
staticmot clé spécifie que la variable conserve son état entre les appels à cette fonction.Lorsque vous déclarez un membre de données dans une déclaration de classe, le
staticmot clé spécifie qu’une copie du membre est partagée par toutes les instances de la classe. Unstaticmembre de données doit être défini au niveau de l’étendue du fichier. Membre de données intégral que vous déclarez commeconst staticpouvant avoir un initialiseur.Lorsque vous déclarez une fonction membre dans une déclaration de classe, le
staticmot clé spécifie que la fonction est partagée par toutes les instances de la classe. Unestaticfonction membre ne peut pas accéder à un membre d’instance, car la fonction n’a pas de pointeur implicitethis. Pour accéder à un membre d’instance, déclarez la fonction avec un paramètre qui est un pointeur d’instance ou une référence.Vous ne pouvez pas déclarer les membres d’un
unionasstatic. Toutefois, un anonymeuniondéclaré globalement doit être déclaréstaticexplicitement.
Cet exemple montre comment une variable déclarée static dans une fonction conserve son état entre les appels à cette fonction.
// 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
Cet exemple montre l’utilisation dans static une 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
L’exemple suivant montre une variable locale déclarée static dans une fonction membre. La static variable est disponible pour l’ensemble du programme ; toutes les instances du type partagent la même copie de la static variable.
// 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
À compter de C++11, une static initialisation de variable locale est garantie d’être thread-safe. Cette fonctionnalité est parfois appelée statique magique. Toutefois, dans une application multithread, toutes les assignations suivantes doivent être synchronisées. La fonctionnalité d’initialisation statique thread-safe peut être désactivée à l’aide de l’indicateur /Zc:threadSafeInit- pour éviter de prendre une dépendance sur le CRT.
extern
Les objets et les variables déclarés comme extern déclarent un objet défini dans une autre unité de traduction ou dans une étendue englobante comme ayant une liaison externe. Pour plus d’informations, consultez extern et unités de traduction et liaison.
thread_local (C++11)
Une variable déclarée avec le thread_local spécificateur est accessible uniquement sur le thread sur lequel il est créé. La variable est créée lorsque le thread est créé et détruit lorsque le thread est détruit. Chaque thread possède sa propre copie de la variable. Sur Windows, thread_local est fonctionnellement équivalent à l’attribut spécifique __declspec( thread ) à 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;
}
Remarques sur le thread_local spécificateur :
Les variables locales de thread initialisées dynamiquement dans les DLL peuvent ne pas être correctement initialisées sur tous les threads appelants. Pour plus d’informations, consultez
thread.Le
thread_localspécificateur peut être combiné avecstaticouextern.Vous ne pouvez s’appliquer
thread_localqu’aux déclarations et définitions de données ;thread_localne peut pas être utilisé sur les déclarations de fonction ou les définitions.Vous pouvez spécifier
thread_localuniquement sur les éléments de données avec une durée de stockage statique, qui inclut des objets de données globaux (à la foisstaticetextern), des objets statiques locaux et des membres de données statiques de classes. Toute variable locale déclaréethread_localest implicitement statique si aucune autre classe de stockage n’est fournie ; en d’autres termes, l’étenduethread_localde bloc est équivalente àthread_local static.Vous devez spécifier
thread_localà la fois pour la déclaration et la définition d'un objet local de thread, que la déclaration et la définition se produisent dans le même fichier ou dans des fichiers séparés.Nous vous déconseillons d’utiliser
thread_localdes variables avecstd::launch::async. Pour plus d’informations, consultez<future>les fonctions.
Sur Windows, thread_local équivaut fonctionnellement à __declspec(thread) ceci près que *__declspec(thread)* peut être appliqué à une définition de type et est valide dans le code C. Dans la mesure du possible, utilisez-le thread_local parce qu’il fait partie de la norme C++ et est donc plus portable.
inscription
Visual Studio 2017 version 15.3 et ultérieure (disponible en /std:c++17 mode et versions ultérieures) : le register mot clé n’est plus une classe de stockage prise en charge. Son utilisation provoque un diagnostic. Le mot clé est toujours réservé dans la norme pour une utilisation ultérieure.
register int val; // warning C5033: 'register' is no longer a supported storage class
Exemple : initialisation automatique et statique
Une variable automatique ou un objet local est initialisé chaque fois que l'ordre d'exécution atteint sa définition. Une variable automatique ou un objet statique est initialisé la première fois que l'ordre d'exécution atteint sa définition.
Prenons l'exemple suivant, qui définit une classe qui stocke l'initialisation et la destruction des objets, puis définit trois objets, I1, I2, et 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
Cet exemple montre comment et quand les objets I1, I2et I3 sont initialisés et quand ils sont détruits.
Il existe plusieurs points à noter sur le programme :
Tout d’abord,
I1etI2sont automatiquement détruits lorsque le flux de contrôle quitte le bloc dans lequel ils sont définis.Deuxièmement, en C++, il n’est pas nécessaire de déclarer des objets ou des variables au début d’un bloc. En outre, ces objets sont initialisés uniquement lorsque l'ordre d'exécution atteint leurs définitions. (
I2etI3sont des exemples de ces définitions.) La sortie s’affiche exactement quand elles sont initialisées.Enfin, les variables locales statiques telles que
I3conserver leurs valeurs pendant l’exécution du programme, mais sont détruites à mesure que le programme se termine.