Megosztás a következőn keresztül:


Tárolási osztályok

A C++ változódeklarációk környezetében található tárolási osztály egy típuskijelölő, amely szabályozza az objektumok élettartamát, összekapcsolását és memóriahelyét. Egy adott objektumnak csak egy tárosztálya lehet. A blokkon belül definiált változók automatikus tárolóval rendelkeznek, kivéve, ha a extern, staticvagy thread_local a kijelölők másként vannak megadva. Az automatikus objektumok és változók nincsenek összekapcsolva; a blokkon kívüli kód nem látható. A rendszer automatikusan lefoglalja a memóriát, amikor a végrehajtás belép a blokkba, és a blokk kilépésekor megszűnik.

Jegyzetek

  • A mutable kulcsszó tárolóosztály-meghatározónak tekinthető. Ez azonban csak egy osztálydefiníció taglistájában érhető el.

  • Visual Studio 2010 és újabb verziók: A auto kulcsszó már nem C++ tárosztály-meghatározó, és a register kulcsszó elavult. Visual Studio 2017 15.7-es és újabb verzió: (módban és később érhető el /std:c++17 ): A register kulcsszó el lesz távolítva a C++ nyelvről. Használata diagnosztikai üzenetet okoz:

    // 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

A static kulcsszó használható változók és függvények globális hatókörben, névtér- és osztályhatókörben történő deklarálásához. A statikus változók helyi hatókörben is deklarálhatók.

A statikus időtartam azt jelenti, hogy az objektum vagy változó a program indításakor lesz lefoglalva, és a program befejezésekor felszabadítja. A külső kapcsolat azt jelenti, hogy a változó neve azon a fájlon kívülről látható, ahol a változó deklarálva van. Ezzel szemben a belső kapcsolat azt jelenti, hogy a név nem látható azon a fájlon kívül, amelyben a változó deklarálva van. Alapértelmezés szerint egy globális névtérben definiált objektum vagy változó statikus időtartammal és külső kapcsolattal rendelkezik. A static kulcsszó a következő helyzetekben használható.

  1. Ha egy változót vagy függvényt fájlhatókörben deklarál (globális és/vagy névtér-hatókör), a static kulcsszó azt határozza meg, hogy a változó vagy függvény belső kapcsolatokkal rendelkezik. Változó deklarálásakor a változó statikus időtartamú, a fordító pedig 0 értékre inicializálja, hacsak nem ad meg másik értéket.

  2. Ha egy függvényben deklarál egy változót, a static kulcsszó azt határozza meg, hogy a változó megtartsa az állapotát a függvény hívásai között.

  3. Amikor egy osztálydeklarációban adattagot deklarál, a static kulcsszó azt határozza meg, hogy a tag egy példányát az osztály összes példánya megosztja. Az static adattagot a fájl hatókörében kell definiálni. Egy inicializálóként deklarált const static , integrált adattag.

  4. Amikor egy tagfüggvényt osztálydeklarációban deklarál, a static kulcsszó azt határozza meg, hogy a függvényt az osztály összes példánya megosztja. A static tagfüggvények nem férnek hozzá a példánytagokhoz, mert a függvény nem rendelkezik implicit this mutatóval. Egy példánytag eléréséhez deklarálja a függvényt egy olyan paraméterrel, amely egy példánymutató vagy hivatkozás.

  5. A tagok union nem deklarálhatók a következőként static: . A globálisan deklarált névtelennek union azonban explicit módon kell deklarálnia static.

Ez a példa bemutatja, hogy egy függvényben deklarált static változó hogyan őrzi meg az állapotát a függvény hívásai között.

// 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

Ez a példa egy static osztály használatát mutatja be.

// 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

Az alábbi példa egy tagfüggvényben deklarált static helyi változót mutat be. A static változó a teljes program számára elérhető; a típus összes példánya ugyanazzal a változóval rendelkezik static .

// 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 C++11-től kezdve a static helyi változó inicializálása garantáltan szálbiztos lesz. Ezt a funkciót néha mágikus statikusnak is nevezik. Többszálú alkalmazásokban azonban minden további hozzárendelést szinkronizálni kell. A szálbiztos statikus inicializálási funkció letiltható a /Zc:threadSafeInit- jelölő használatával, hogy elkerülje a CRT-függőséget.

extern

A deklarált objektumok és változók deklarált extern objektumként vannak meghatározva egy másik fordítási egységben vagy egy olyan hatókörben, amely külső kapcsolatokkal rendelkezik. További információkért lásd extern a fordítási egységeket és a csatolást.

thread_local (C++11)

A megadóval thread_local deklarált változó csak azon a szálon érhető el, amelyen létrehozta. A változó a szál létrehozásakor jön létre, és a szál megsemmisítésekor megsemmisül. Minden szál saját másolatot készít a változóról. Windows thread_local rendszeren funkcionálisan egyenértékű a Microsoft-specifikus __declspec( thread ) attribútummal.

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;
}

A megadóval kapcsolatos thread_local tudnivalók:

  • Előfordulhat, hogy a dll-ekben a dinamikusan inicializált szál helyi változói nem inicializálhatók megfelelően az összes hívószálon. További információért lásd thread.

  • A thread_local kijelölő kombinálható a következővel static : vagy extern.

  • Csak adatdeklarációkra és definíciókra alkalmazható thread_local ; thread_local függvénydeklarációkban és definíciókban nem használható.

  • Csak statikus tárolási időtartamú adatelemeket adhat meg thread_local , amelyek globális adatobjektumokat (mindkettőt static és), helyi statikus objektumokat és externosztályok statikus adattagjait is magukban foglalják. A deklarált helyi változók implicit módon statikusak, ha nem ad thread_local meg más tárolási osztályt, más szóval a blokk hatóköre thread_local egyenértékű a thread_local static.

  • Meg kell adnia thread_local mind a deklarációt, mind a szál helyi objektumának definícióját, függetlenül attól, hogy a deklaráció és a definíció ugyanabban a fájlban vagy különálló fájlokban történik-e.

  • Nem javasoljuk, hogy változókat használjon thread_local a következővel std::launch::async: . További információ: <future> függvények.

Windows rendszeren funkcionálisan egyenértékű __declspec(thread) azzal, thread_local hogy *__declspec(thread)a * típusdefinícióra alkalmazható, és C-kódban érvényes. Amikor csak lehetséges, használja thread_local , mert a C++ szabvány része, ezért hordozhatóbb.

regiszter

Visual Studio 2017 15.3-s és újabb verzió (módban és újabb verziókban /std:c++17 érhető el): A register kulcsszó már nem támogatott tárolási osztály. Használata diagnosztikát okoz. A kulcsszó továbbra is a szabványban van fenntartva későbbi használatra.

   register int val; // warning C5033: 'register' is no longer a supported storage class

Példa: automatikus és statikus inicializálás

A helyi automatikus objektum vagy változó minden alkalommal inicializálódik, amikor a vezérlőfolyamat eléri a definícióját. A helyi statikus objektumok vagy változók inicializálása akkor történik, amikor a vezérlőfolyamat első alkalommal eléri a definícióját.

Vegyük az alábbi példát, amely egy olyan osztályt határoz meg, amely naplózza az objektumok inicializálását és megsemmisítését, majd definiál három objektumot, I1I2ésI3:

// 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

Ez a példa bemutatja, hogyan és mikor vannak inicializálva és megsemmisítve az objektumokI1I2I3.

A programról több megjegyzést is érdemes megjegyezni:

  • Először is, I1 és I2 automatikusan megsemmisül, amikor a vezérlési folyamat kilép a blokkból, amelyben definiálva vannak.

  • Másodszor, a C++-ban nem szükséges objektumokat vagy változókat deklarálni a blokk elején. Továbbá ezek az objektumok csak akkor inicializálódnak, ha a vezérlőfolyamat eléri a definícióikat. (I2 és I3 példák ezekre a definíciókra.) A kimenet pontosan akkor jelenik meg, amikor inicializálva vannak.

  • Végül a statikus helyi változók, például I3 megtartják az értékeiket a program futtatásakor, de a program leállásakor elvesznek.

Lásd még

Deklarációk és definíciók