Speicherklassen
Eine Speicherklasse im Kontext von C++-Variablendeklarationen ist ein Typbezeichner, der die Lebensdauer, Verknüpfung und Speicherort von Objekten steuert. Ein angegebenes Objekt kann nur eine Speicherklasse haben. Variablen, die in einem Block definiert sind, weisen automatischen Speicher auf, sofern dies nicht mit den extern
static
Bezeichnern oder thread_local
Bezeichnern anders angegeben wird. Automatische Objekte und Variablen haben keine Verknüpfung; sie sind für Code außerhalb des Blocks nicht sichtbar. Der Speicher wird automatisch zugewiesen, wenn die Ausführung in den Block wechselt und beim Beenden des Blocks aufgehoben wird.
Hinweise
Die
mutable
Schlüsselwort (keyword) kann als Speicherklassenbezeichner betrachtet werden. Sie ist jedoch nur in der Memberliste einer Klassendefinition verfügbar.Visual Studio 2010 und höher: Die
auto
Schlüsselwort (keyword) ist kein C++-Speicherklassenbezeichner mehr, und dieregister
Schlüsselwort (keyword) ist veraltet. Visual Studio 2017, Version 15.7 und höher: (im/std:c++17
Modus und höher verfügbar): Dieregister
Schlüsselwort (keyword) wird aus der C++-Sprache entfernt. Die Verwendung bewirkt eine Diagnosenachricht:// 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
Die static
Schlüsselwort (keyword) können verwendet werden, um Variablen und Funktionen im globalen Bereich, Namespacebereich und Klassenbereich zu deklarieren. Statische Variablen können auch im lokalen Gültigkeitsbereich deklariert werden.
Statische Dauer bedeutet, dass das Objekt oder die Variable zugewiesen wird, wenn das Programm gestartet wird. Die Zuweisung wird wieder aufgehoben, wenn das Programm beendet wird. Externe Verknüpfung bedeutet, dass der Name der Variablen außerhalb der Datei sichtbar ist, in der die Variable deklariert wird. Im Gegensatz dazu bedeutet die interne Verknüpfung, dass der Name außerhalb der Datei, in der die Variable deklariert wird, nicht sichtbar ist. Standardmäßig verfügt ein Objekt oder eine Variable, das bzw. die im globalen Namespace definiert wird, über eine statische Dauer und externe Verknüpfung. Die static
Schlüsselwort (keyword) können in den folgenden Situationen verwendet werden.
Wenn Sie eine Variable oder Funktion im Dateibereich (globaler und/oder Namespacebereich) deklarieren, gibt die
static
Schlüsselwort (keyword) an, dass die Variable oder Funktion über eine interne Verknüpfung verfügt. Wenn Sie eine Variable deklarieren, hat die Variable eine statische Dauer und wird vom Compiler mit dem Wert 0 initialisiert, solange Sie keinen anderen Wert angeben.Wenn Sie eine Variable in einer Funktion deklarieren, gibt die
static
Schlüsselwort (keyword) an, dass die Variable ihren Zustand zwischen Aufrufen dieser Funktion behält.Wenn Sie ein Datenmembe in einer Klassendeklaration deklarieren, gibt die
static
Schlüsselwort (keyword) an, dass eine Kopie des Elements von allen Instanzen der Klasse gemeinsam verwendet wird. Einstatic
Datenmememm muss im Dateibereich definiert werden. Ein integrales Datenelement, das Sie als Initialisierer deklarierenconst static
.Wenn Sie eine Memberfunktion in einer Klassendeklaration deklarieren, gibt die
static
Schlüsselwort (keyword) an, dass die Funktion von allen Instanzen der Klasse gemeinsam verwendet wird. Einestatic
Memberfunktion kann nicht auf ein Instanzelement zugreifen, da die Funktion keinen implizitenthis
Zeiger hat. Um auf ein Instanzmememm zuzugreifen, deklarieren Sie die Funktion mit einem Parameter, der einen Instanzzeiger oder -verweis darstellt.Sie können die Member einer
union
Alsstatic
nicht deklarieren. Allerdings muss eine global deklarierte anonymeunion
Person explizit deklariertstatic
werden.
In diesem Beispiel wird gezeigt, wie eine in einer Funktion deklarierte static
Variable ihren Zustand zwischen Aufrufen dieser Funktion behält.
// 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
Dieses Beispiel zeigt die Verwendung static
in einer Klasse.
// 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
Das folgende Beispiel zeigt eine lokale Variable, die in einer Memberfunktion deklariert ist static
. Die static
Variable ist für das gesamte Programm verfügbar. Alle Instanzen des Typs verwenden dieselbe Kopie der static
Variablen.
// 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
Ab C++11 static
ist eine lokale Variableninitialisierung garantiert threadsicher. Dieses Feature wird manchmal als magische Statik bezeichnet. Allerdings müssen alle nachfolgende Zuweisungen in einer Multithreadanwendung synchronisiert werden. Die threadsichere statische Initialisierungsfunktion kann mithilfe des /Zc:threadSafeInit-
Flags deaktiviert werden, um zu vermeiden, dass eine Abhängigkeit vom CRT verwendet wird.
extern
Objekte und Variablen, die als extern
Deklarieren eines Objekts deklariert werden, das in einer anderen Übersetzungseinheit oder in einem eingeschlossenen Bereich als externe Verknüpfung definiert ist. Weitere Informationen finden Sie unter extern
Übersetzungseinheiten und Verknüpfungen.
thread_local
(C++11)
Auf eine variable, die mit dem thread_local
Bezeichner deklariert wird, kann nur im Thread zugegriffen werden, auf den sie erstellt wird. Die Variable wird erstellt, wenn der Thread erstellt wird, und er wird zerstört, wenn der Thread zerstört wird. Jeder Thread verfügt über eine eigene Kopie der Variable. Unter Windows thread_local
entspricht die Funktion dem microsoftspezifischen __declspec( thread )
Attribut.
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;
}
Hinweise zum thread_local
Bezeichner:
Dynamisch initialisierte threadlokale Variablen in DLLs werden in allen aufrufenden Threads möglicherweise nicht ordnungsgemäß initialisiert. Weitere Informationen finden Sie unter
thread
.Der
thread_local
Bezeichner kann mitstatic
oderextern
.Sie können nur auf Datendeklarationen und Definitionen angewendet
thread_local
werden.thread_local
Sie können nicht für Funktionsdeklarationen oder Definitionen verwendet werden.Sie können nur für Datenelemente mit statischer Speicherdauer angeben
thread_local
, die globale Datenobjekte (sowohl alsextern
auchstatic
), lokale statische Objekte und statische Datenelemente von Klassen umfasst. Jede deklariertethread_local
lokale Variable ist implizit statisch, wenn keine andere Speicherklasse bereitgestellt wird, d. h. im Blockbereichthread_local
entsprichtthread_local static
.Sie müssen das
thread_local
für die Deklaration und Definition eines lokalen Threadobjekts angeben, egal ob die Deklaration und Definition in der gleichen Datei oder in separaten Dateien auftreten.Es wird nicht empfohlen,
thread_local
Variablen mitstd::launch::async
. Weitere Informationen finden Sie unter<future>
Funktionen.
Unter Windows ist funktional gleichbedeutend mit __declspec(thread)
der Ausnahme, thread_local
dass *__declspec(thread)
* auf eine Typdefinition angewendet werden kann und in C-Code gültig ist. Verwenden Sie thread_local
nach Möglichkeit, da sie Teil des C++-Standards ist und daher portierbarer ist.
Registrieren
Visual Studio 2017, Version 15.3 und höher (im /std:c++17
Modus und höher verfügbar): Die register
Schlüsselwort (keyword) ist keine unterstützte Speicherklasse mehr. Die Verwendung bewirkt eine Diagnose. Die Schlüsselwort (keyword) ist weiterhin im Standard für die zukünftige Verwendung reserviert.
register int val; // warning C5033: 'register' is no longer a supported storage class
Beispiel: automatische und statische Initialisierung
Ein lokales automatisches Objekt oder eine lokale automatische Variable wird jedes Mal initialisiert, wenn die Ablaufsteuerung ihre Definition erreicht. Ein lokales automatisches Objekt oder eine lokale automatische Variable wird erstmalig initialisiert, wenn die Ablaufsteuerung ihre Definition erreicht.
Betrachten Sie das folgende Beispiel, in dem eine Klasse definiert wird, die die Initialisierung und Beschädigung von Objekten protokolliert und dann drei Objekte, I1
, I2
und I3
, definiert:
// 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 diesem Beispiel wird veranschaulicht, wie und wann die Objekte I1
I2
, und wann sie zerstört werden.I3
Es gibt mehrere Punkte, die sie zu dem Programm beachten müssen:
Zuerst und
I2
werden automatisch zerstört,I1
wenn der Kontrollfluss den Block verlässt, in dem sie definiert sind.Zweitens ist es in C++ nicht erforderlich, Objekte oder Variablen am Anfang eines Blocks zu deklarieren. Außerdem werden diese Objekte nur initialisiert, wenn die Ablaufsteuerung deren Definitionen erreicht. (
I2
beispieleI3
für solche Definitionen.) Die Ausgabe zeigt genau an, wann sie initialisiert werden.Schließlich werden statische lokale Variablen, z
I3
. B. ihre Werte beibehalten, während das Programm ausgeführt wird, aber zerstört, wenn das Programm beendet wird.
Siehe auch
Feedback
https://aka.ms/ContentUserFeedback.
Bald verfügbar: Im Laufe des Jahres 2024 werden wir GitHub-Issues stufenweise als Feedbackmechanismus für Inhalte abbauen und durch ein neues Feedbacksystem ersetzen. Weitere Informationen finden Sie unterFeedback senden und anzeigen für