Aracılığıyla paylaş


Depolama sınıfları

C++ değişken bildirimleri bağlamında bir depolama sınıfı, nesnelerin yaşam süresi, bağlantı ve bellek konumunu yöneten bir tür tanımlayıcıdır. Belirli bir nesnenin yalnızca bir depolama sınıfı olabilir. Bir blok içinde tanımlanan değişkenler, , staticveya thread_local tanımlayıcıları kullanılarak aksi belirtilmedikçe otomatik depolamaya externsahiptir. Otomatik nesnelerin ve değişkenlerin bağlantısı yoktur; blok dışındaki kodlar görünür değildir. Yürütme bloğa girdiğinde bunlar için bellek otomatik olarak ayrılır ve blok çıkıldığında bu bellek ayrılır.

Notlar

  • anahtar mutable sözcüğü bir depolama sınıfı tanımlayıcısı olarak kabul edilebilir. Ancak, yalnızca bir sınıf tanımının üye listesinde kullanılabilir.

  • Visual Studio 2010 ve üzeri: Anahtar auto sözcük artık bir C++ depolama sınıfı tanımlayıcısı değildir ve register anahtar sözcük kullanım dışıdır. Visual Studio 2017 sürüm 15.7 ve üzeri: (mod ve sonraki sürümlerde /std:c++17 kullanılabilir): register Anahtar sözcük C++ dilinden kaldırılır. Kullanımı bir tanılama iletisine neden olur:

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

anahtar static sözcüğü genel kapsamda, ad alanı kapsamında ve sınıf kapsamında değişkenleri ve işlevleri bildirmek için kullanılabilir. Statik değişkenler yerel kapsamda da bildirilebilir.

Statik süre, nesnenin veya değişkenin program başlatıldığında ayrıldığı ve program sona erdiğinde serbest bırakıldığı anlamına gelir. Dış bağlantı, değişkenin adının değişkenin bildirildiği dosyanın dışından görüleceği anlamına gelir. Buna karşılık iç bağlantı, adın değişkenin bildirildiği dosyanın dışında görünmediği anlamına gelir. Varsayılan olarak, genel ad alanında tanımlanan bir nesnenin veya değişkenin statik süresi ve dış bağlantısı vardır. anahtar static sözcüğü aşağıdaki durumlarda kullanılabilir.

  1. Dosya kapsamında (genel ve/veya ad alanı kapsamı) static bir değişken veya işlev bildirdiğinizde, anahtar sözcüğü değişkenin veya işlevin iç bağlantısı olduğunu belirtir. Bir değişken bildirdiğinizde, değişkenin statik süresi vardır ve siz başka bir değer belirtmediğiniz sürece derleyici bunu 0 olarak başlatır.

  2. Bir işlevde değişken bildirdiğinizde, static anahtar sözcüğü değişkenin bu işleve yapılan çağrılar arasında durumunu koruduğunu belirtir.

  3. Bir sınıf bildiriminde bir veri üyesi bildirdiğinizde anahtar sözcüğü, static üyenin bir kopyasının sınıfın tüm örnekleri tarafından paylaşıldığını belirtir. Veri static üyesi dosya kapsamında tanımlanmalıdır. olarak const static bildirdiğiniz bir integral veri üyesinin başlatıcısı olabilir.

  4. Bir sınıf bildiriminde üye işlevi bildirdiğinizde, static anahtar sözcüğü işlevin sınıfın tüm örnekleri tarafından paylaşıldığını belirtir. static İşlevin örtük this işaretçisi olmadığından üye işlev örnek üyesine erişemiyor. Örnek üyesine erişmek için, işlevi örnek işaretçisi veya başvuru olan bir parametreyle bildirin.

  5. üyelerini union olarak staticbildiremezsiniz. Ancak, genel olarak bildirilen anonim union açıkça bildirilmelidir static.

Bu örnek, bir işlevde bildirilen static bir değişkenin, bu işleve yapılan çağrılar arasında durumunu nasıl koruduğunu gösterir.

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

Bu örnekte bir sınıfta kullanımı gösterilmektedir static .

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

Aşağıdaki örnekte, üye işlevinde bildirilen static yerel bir değişken gösterilmektedir. değişkeni static tüm program tarafından kullanılabilir; türün tüm örnekleri değişkenin aynı kopyasını static paylaşır.

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

C++11'den başlayarak yerel static değişken başlatmanın iş parçacığı açısından güvenli olması garanti edilir. Bu özellik bazen sihirli statik olarak adlandırılır. Ancak, çok iş parçacıklı bir uygulamada sonraki tüm atamaların eşitlenmesi gerekir. İş parçacığı güvenli statik başlatma özelliği, CRT'ye bağımlılık almamak için bayrağı kullanılarak /Zc:threadSafeInit- devre dışı bırakılabilir.

extern

Olarak extern bildirilen nesneler ve değişkenler, başka bir çeviri biriminde veya kapsayan bir kapsamda dış bağlantıya sahip olarak tanımlanan bir nesne bildirir. Daha fazla bilgi için bkz extern . çeviri birimleri ve bağlantısı.

thread_local (C++11)

Tanımlayıcı ile thread_local bildirilen bir değişkene yalnızca oluşturulduğu iş parçacığında erişilebilir. Değişken, iş parçacığı oluşturulduğunda oluşturulur ve iş parçacığı yok edildiğinde yok edilir. Her iş parçacığının kendi değişkeni kopyası vardır. Windows'ta, thread_local işlevsel olarak Microsoft'a özgü __declspec( thread ) öznitelikle eşdeğerdir.

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

Tanımlayıcı hakkında thread_local dikkate alınacak noktalar:

  • DLL'lerde dinamik olarak başlatılan iş parçacığı yerel değişkenleri tüm çağrı iş parçacıklarında doğru başlatılamayabilir. Daha fazla bilgi için bkz. thread.

  • Tanımlayıcı thread_local veya externile static birleştirilebilir.

  • Yalnızca veri bildirimlerine ve tanımlarına uygulayabilirsiniz thread_local ; thread_local işlev bildirimlerinde veya tanımlarında kullanılamaz.

  • Yalnızca genel veri nesnelerini (hem hem de staticextern), yerel statik nesneleri ve sınıfların statik veri üyelerini içeren statik depolama süresine sahip veri öğelerini belirtebilirsinizthread_local. Bildirilen thread_local herhangi bir yerel değişken, başka bir depolama sınıfı sağlanmadıysa örtük olarak statiktir; başka bir deyişle, blok kapsamında thread_local ile thread_local staticeşdeğerdir.

  • Bildirimin ve tanımın aynı dosyada mı yoksa ayrı dosyalarda mı yer alması fark etmeksizin, hem bildirim hem de iş parçacığı yerel nesnesinin tanımı için belirtmelisiniz thread_local .

  • ile std::launch::asyncdeğişkenleri kullanmanızı thread_local önermiyoruz. Daha fazla bilgi için bkz <future> . işlevler.

Windows'da, thread_local * türü tanımına __declspec(thread) uygulanabilmesi ve C kodunda geçerli olması dışında *__declspec(thread), ile işlevsel olarak eşdeğerdir. Mümkün olduğunda, C++ standardının bir parçası olduğundan ve bu nedenle daha taşınabilir olduğundan kullanın thread_local .

register

Visual Studio 2017 sürüm 15.3 ve üzeri (mod ve sonraki sürümlerde /std:c++17 kullanılabilir): register Anahtar sözcük artık desteklenen bir depolama sınıfı değildir. Kullanımı bir tanılamaya neden olur. Anahtar sözcük, gelecekte kullanılmak üzere yine de standart olarak ayrılmıştır.

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

Örnek: otomatik ve statik başlatma

Denetim akışı tanımına her ulaştığında yerel bir otomatik nesne veya değişken başlatılır. Yerel statik nesne veya değişken, denetim akışı tanımına ilk kez ulaştığında başlatılır.

Nesnelerin başlatılmasını ve yok edilmesini günlüğe kaydeden bir sınıfı tanımlayan ve ardından , ve I3olmak üzere üç nesne I1I2tanımlayan aşağıdaki örneği düşünün:

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

Bu örnekte , I2I3 ve nesnelerinin I1nasıl ve ne zaman başlatıldığı ve ne zaman yok edildiği gösterilmektedir.

Program hakkında dikkate almak için birkaç nokta vardır:

  • İlk olarak ve I1I2 denetim akışı tanımlandıkları blokta çıktığında otomatik olarak yok edilir.

  • İkinci olarak, C++ dilinde bir bloğun başında nesne veya değişken bildirmek gerekli değildir. Ayrıca, bu nesneler yalnızca denetim akışı tanımlarına ulaştığında başlatılır. (I2 ve I3 bu tür tanımların örnekleridir.) Çıkış tam olarak ne zaman başlatıldıklarını gösterir.

  • Son olarak, program çalışırken değerleri gibi I3 statik yerel değişkenler korunur, ancak program sonlandırıldıkçe yok edilir.

Ayrıca bkz.

Bildirimler ve Tanımlar