Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Třída úložiště v kontextu deklarací proměnných jazyka C++ je specifikátor typu, který řídí životnost, propojení a umístění paměti objektů. Předaný objekt může mít pouze jednu třídu úložiště. Proměnné definované v rámci bloku mají automatické úložiště, pokud neurčíte jinak pomocí externspecifikátorů , staticnebo thread_local specifikátorů. Automatické objekty a proměnné nemají žádné propojení; nejsou viditelné pro kód mimo blok. Paměť se pro ně při zadávání bloku automaticky přidělí a při ukončení bloku se zruší přidělení.
Notes
Klíčové
mutableslovo může být považováno za specifikátor třídy úložiště. Je však k dispozici pouze v seznamu členů definice třídy.Visual Studio 2010 a novější: Klíčové
autoslovo už není specifikátorem třídy úložiště C++ aregisterklíčové slovo je zastaralé. Visual Studio 2017 verze 15.7 a novější: (dostupné v/std:c++17režimu a novější): Klíčovéregisterslovo se odebere z jazyka C++. Jeho použití způsobí diagnostickou zprávu:// 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
Klíčové static slovo lze použít k deklaraci proměnných a funkcí v globálním oboru, oboru názvů a oboru třídy. Statické proměnné lze deklarovat také v místním oboru.
Statická doba trvání znamená, že objekt nebo proměnná se při spuštění programu přidělí a uvolní se při ukončení programu. Externí propojení znamená, že název proměnné je viditelný mimo soubor, ve kterém je proměnná deklarována. Naopak interní propojení znamená, že název není viditelný mimo soubor, kde je proměnná deklarována. Ve výchozím nastavení má objekt nebo proměnnou definovanou v globálním oboru názvů statickou dobu trvání a externí propojení. Klíčové static slovo lze použít v následujících situacích.
Když deklarujete proměnnou nebo funkci v oboru souborů (globální obor oboru názvů nebo oboru názvů),
staticklíčové slovo určuje, že proměnná nebo funkce má interní propojení. Když deklarujete proměnnou, má proměnná statickou dobu trvání a kompilátor ji inicializuje na hodnotu 0, pokud nezadáte jinou hodnotu.Když deklarujete proměnnou ve funkci, klíčové slovo určuje,
staticže proměnná uchovává svůj stav mezi voláními této funkce.Když deklarujete datový člen v deklaraci třídy,
staticklíčové slovo určuje, že jedna kopie člena je sdílena všemi instancemi třídy. Datovýstaticčlen musí být definován v oboru souboru. Integrální datový člen, který deklarujete jakoconst staticmůže mít inicializátor.Když deklarujete členskou funkci v deklaraci třídy,
staticklíčové slovo určuje, že funkce je sdílena všemi instancemi třídy. Členovástaticfunkce nemůže získat přístup k členu instance, protože funkce nemá implicitníthisukazatel. Pokud chcete získat přístup k členu instance, deklarujte funkci pomocí parametru, který je ukazatelem instance nebo odkazem.Nemůžete deklarovat členy
unionjakostatic. Globálně deklarovaný anonymníunionvšak musí být explicitně deklarovánstatic.
Tento příklad ukazuje, jak proměnná deklarovaná static ve funkci zachovává svůj stav mezi voláními této funkce.
// 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
Tento příklad ukazuje použití static ve třídě.
// 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
Následující příklad ukazuje místní proměnnou deklarovanou static v členské funkci. Proměnná static je k dispozici pro celý program; všechny instance typu sdílejí stejnou kopii static proměnné.
// 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
Od C++11 je zaručeno, static že inicializace místních proměnných je bezpečná pro přístup z více vláken. Tato funkce se někdy označuje jako magická statická. Ve vícevláknové aplikaci je však nutné synchronizovat všechna následná přiřazení. Pomocí příznaku /Zc:threadSafeInit- lze zakázat funkci statické inicializace bezpečné pro přístup z více vláken, aby se zabránilo závislosti na CRT.
extern
Objekty a proměnné deklarované jako extern deklarují objekt, který je definován v jiné jednotce překladu nebo v uzavřeném oboru, jako má externí propojení. Další informace najdete v článcích extern a jednotkách překladu a propojení.
thread_local (C++11)
Proměnná deklarovaná pomocí specifikátoru thread_local je přístupná pouze ve vlákně, na kterém je vytvořena. Proměnná se vytvoří při vytvoření vlákna a je zničena při zničení vlákna. Každé vlákno má vlastní kopii proměnné. Ve Windows thread_local je funkčně ekvivalentní atributu specifickému pro __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;
}
Co je potřeba vědět o specifikátoru thread_local :
Dynamicky inicializované proměnné thread-local v knihovnách DLL nemusí být správně inicializovány ve všech volajících vláknech. Další informace najdete na webu
thread.thread_localSpecifikátor může být kombinován sstaticneboextern.Můžete použít
thread_localpouze u deklarací a definic dat.thread_localNejde použít u deklarací funkcí nebo definic.Můžete zadat
thread_localpouze datové položky se statickou dobou trvání úložiště, která zahrnuje globální datové objekty (astaticextern), místní statické objekty a statické datové členy tříd. Jakákoli místní proměnná deklarovanáthread_localimplicitně statická, pokud není k dispozici žádná jiná třída úložiště; jinými slovy, v rozsahuthread_localbloku je ekvivalentníthread_local static.Je nutné zadat
thread_localpro deklaraci i definici místního objektu vlákna, zda deklarace a definice probíhají ve stejném souboru nebo v samostatných souborech.Nedoporučujeme používat
thread_localproměnné sstd::launch::async. Další informace najdete v tématu<future>funkce.
Ve Windows je funkčně ekvivalentní s tím rozdílemthread_local, __declspec(thread) že *__declspec(thread)* lze použít na definici typu a je platný v kódu jazyka C. Kdykoli je to možné, použijte thread_local ji, protože je součástí standardu C++, a proto je přenosnější.
registr
Visual Studio 2017 verze 15.3 a novější (dostupné v /std:c++17 režimu a novější): Klíčové register slovo už není podporovanou třídou úložiště. Jeho použití způsobuje diagnostiku. Klíčové slovo je stále rezervované ve standardu pro budoucí použití.
register int val; // warning C5033: 'register' is no longer a supported storage class
Příklad: automatická vs. statická inicializace
Místní automatický objekt nebo proměnná se inicializuje pokaždé, když tok řízení dosáhne své definice. Místní statický objekt nebo proměnná se inicializuje při prvním dosažení definice toku řízení.
Představte si následující příklad, který definuje třídu, která zaznamenává inicializaci a zničení objektů a pak definuje tři objekty, I1a I2I3:
// 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
Tento příklad ukazuje, jak a kdy objekty I1, I2a I3 jsou inicializovány a kdy jsou zničeny.
Existuje několik bodů, které je potřeba poznamenat o programu:
Za prvé, a
I1jsou automaticky zničeny,I2když tok řízení ukončí blok, ve kterém jsou definovány.Za druhé v jazyce C++ není nutné deklarovat objekty ani proměnné na začátku bloku. Tyto objekty jsou navíc inicializovány pouze v případě, že tok řízení dosáhne svých definic. (
I2aI3jsou příklady těchto definic.) Výstup ukazuje, kdy jsou inicializovány.Nakonec statické místní proměnné, jako
I3je zachování jejich hodnot při spuštění programu, ale jsou zničeny při ukončení programu.