ストレージ クラス (C++)Storage classes (C++)

Aストレージ クラスC++ のコンテキストでの変数宣言は、オブジェクトの有効期間、リンケージ、およびメモリの場所を制御する型指定子。A storage class in the context of C++ variable declarations is a type specifier that governs the lifetime, linkage, and memory location of objects. 特定のオブジェクトはストレージ クラスを 1 つのみ持つことができます。A given object can have only one storage class. それ以外の場合を使用して指定されていない場合、ブロック内で定義されている変数は自動ストレージを持ちます、 extern静的、またはthread_local指定子。Variables defined within a block have automatic storage unless otherwise specified using the extern, static, or thread_local specifiers. 自動オブジェクトおよび変数にはリンケージがないため、ブロックの外側のコードには不可視です。Automatic objects and variables have no linkage; they are not visible to code outside the block.

ノートNotes

  1. 変更可能なキーワードが、ストレージ クラス指定子として見なされます。The mutable keyword may be considered a storage class specifier. ただし、クラス定義のメンバー一覧でのみ使用できます。However, it is only available in the member list of a class definition.

  2. Visual Studio 2010 以降の場合: 自動キーワードは C++ ストレージ クラス指定子では不要になったと登録キーワードは非推奨とされます。Visual Studio 2010 and later: The auto keyword is no longer a C++ storage-class specifier, and the register keyword is deprecated. Visual Studio 2017 バージョン 15.7 以降: (で使用可能な/std:c + + 17)。登録キーワードは C++ 言語から削除されます。Visual Studio 2017 version 15.7 and later: (available with /std:c++17): The register keyword is removed from the C++ language.

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

このセクションの内容:In this section:

静的static

静的キーワードを使用して、変数やグローバル スコープ、名前空間スコープ、およびクラス スコープで関数を宣言することができます。The static keyword can be used to declare variables and functions at global scope, namespace scope, and class scope. 静的変数は、ローカル スコープでも宣言できます。Static variables can also be declared at local scope.

静的存続期間は、オブジェクトまたは変数がプログラム起動時に割り当てられ、プログラムの終了時に解放されることを意味します。Static duration means that the object or variable is allocated when the program starts and is deallocated when the program ends. 外部リンケージは、変数が宣言されたファイルの外部から変数名が参照できることを意味します。External linkage means that the name of the variable is visible from outside the file in which the variable is declared. 逆に、内部リンケージは、変数が宣言されたファイルの外部でその名前を参照できないことを意味します。Conversely, internal linkage means that the name is not visible outside the file in which the variable is declared. 既定では、グローバル名前空間で定義されたオブジェクトまたは変数には静的存続期間と外部リンケージがあります。By default, an object or variable that is defined in the global namespace has static duration and external linkage. 静的キーワードは、次の状況で使用することができます。The static keyword can be used in the following situations.

  1. 変数またはファイルのスコープで関数を宣言する場合 (グローバルまたは名前空間スコープ)、静的キーワードは、変数または関数が、内部リンケージを持つことを指定します。When you declare a variable or function at file scope (global and/or namespace scope), the static keyword specifies that the variable or function has internal linkage. 変数を宣言すると、変数は静的存続期間が設定され、コンパイラによって 0 に初期化されます (別の値を指定していない場合)。When you declare a variable, the variable has static duration and the compiler initializes it to 0 unless you specify another value.

  2. 関数で変数を宣言するときに、静的キーワードは、変数がその関数呼び出しの間には、その状態を保持することを指定します。When you declare a variable in a function, the static keyword specifies that the variable retains its state between calls to that function.

  3. クラス宣言でのデータ メンバーを宣言するときに、静的キーワードは、メンバーの 1 つのコピーが、クラスのすべてのインスタンスで共有されることを指定します。When you declare a data member in a class declaration, the static keyword specifies that one copy of the member is shared by all instances of the class. 静的データ メンバーはファイル スコープで定義する必要があります。A static data member must be defined at file scope. 整数データ メンバーとして宣言するconst 静的初期化子を持つことができます。An integral data member that you declare as const static can have an initializer.

  4. クラス宣言でメンバー関数を宣言するときに、静的キーワードは、関数がクラスのすべてのインスタンスで共有されることを指定します。When you declare a member function in a class declaration, the static keyword specifies that the function is shared by all instances of the class. 静的メンバー関数は、関数は、暗黙の型があるないために、インスタンス メンバーにアクセスできませんこのポインター。A static member function cannot access an instance member because the function does not have an implicit this pointer. インスタンス メンバーにアクセスするには、インスタンスのポインターまたは参照であるパラメーターを受け取る関数を宣言します。To access an instance member, declare the function with a parameter that is an instance pointer or reference.

  5. 共用体のメンバーを static として宣言することはできません。You cannot declare the members of a union as static. グローバルに宣言された匿名共用体に明示的に宣言する必要がありますが、静的します。However, a globally declared anonymous union must be explicitly declared static.

この例では、変数の宣言方法静的関数でその関数呼び出しの間には、その状態を保持します。This example shows how a variable declared static in a function retains its state between calls to that function.

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

この例の使用を示しています。静的クラスでします。This example shows the use of static in a class.

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

この例で宣言されたローカル変数静的メンバー関数。This example shows a local variable declared static in a member function. 静的変数は、プログラム全体で使用できます。型のすべてのインスタンスは、静的変数の同じコピーを共有します。The static variable is available to the whole program; all instances of the type share the same copy of the 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

C++11 以降では、静的ローカル変数の初期化はスレッド セーフであることが保証されています。Starting in C++11, a static local variable initialization is guaranteed to be thread-safe. この機能が呼ばマジック スタティックします。This feature is sometimes called magic statics. ただし、マルチスレッド アプリケーションでは、後続の割り当てはすべて同期する必要があります。However, in a multithreaded application all subsequent assignments must be synchronized. 使用して、スレッド セーフな静的な初期化の機能を無効にすることができます、 /Zc:threadSafeInit- CRT に依存することを回避するフラグ。The thread-safe static initialization feature can be disabled by using the /Zc:threadSafeInit- flag to avoid taking a dependency on the CRT.

externextern

オブジェクトおよび変数として宣言されているextern別の翻訳単位または外側のスコープ外部リンケージを持つものとして定義されているオブジェクトを宣言します。Objects and variables declared as extern declare an object that is defined in another translation unit or in an enclosing scope as having external linkage.

宣言constで変数をexternストレージ クラスが外部リンケージを持つ変数を強制します。Declaration of const variables with the extern storage class forces the variable to have external linkage. 初期化、 extern const変数が定義する翻訳単位で許可されています。An initialization of an extern const variable is allowed in the defining translation unit. 定義している翻訳単位以外の翻訳単位の初期化は未定義の結果になります。Initializations in translation units other than the defining translation unit produce undefined results. 詳細については、次を参照してくださいextern リンケージの指定を使用した。For more information, see Using extern to Specify Linkage

/Zc: externconstexprコンパイラ オプションは、適用するコンパイラ外部リンケージを使用して宣言された変数にextern constexprします。The /Zc:externConstexpr compiler option causes the compiler to apply external linkage to variables declared by using extern constexpr. 以前のバージョンの Visual Studio で、既定の場合、または /Zc:externConstexpr- を指定すると、Visual Studio に内部リンケージを適用するconstexpr変数場合でも、 externキーワードを使用します。In earlier versions of Visual Studio, and by default or if /Zc:externConstexpr- is specified, Visual Studio applies internal linkage to constexpr variables even if the extern keyword is used. /Zc: externconstexprオプションは、Visual Studio 2017 Update 15.6 以降を使用します。The /Zc:externConstexpr option is available starting in Visual Studio 2017 Update 15.6. 既定で無効であるとします。and is off by default. 促す/permissive-オプションには、/zc: externconstexpr が有効にしません。The /permissive- option does not enable /Zc:externConstexpr.

次のコードは 2 つextern宣言、 DefinedElsewhere (これは別の翻訳単位で定義された名前を参照) とDefinedHere(これは外側のスコープで定義された名前を参照)。The following code shows two extern declarations, DefinedElsewhere (which refers to a name defined in a different translation unit) and DefinedHere (which refers to a name defined in an enclosing scope):

// external.cpp
// DefinedElsewhere is defined in another translation unit
extern int DefinedElsewhere;
int main() {
   int DefinedHere;
   {
      // refers to DefinedHere in the enclosing scope
      extern int DefinedHere;
   }
}

thread_local (c++ 11)thread_local (C++11)

thread_local 指定子で宣言された変数は、それが作成されたスレッドでのみアクセスできます。A variable declared with the thread_local specifier is accessible only on the thread on which it is created. 変数は、スレッドが作成されるときに作成され、スレッドが破棄されるときに破棄されます。The variable is created when the thread is created, and destroyed when the thread is destroyed. 各スレッドには、それ自体の変数のコピーがあります。Each thread has its own copy of the variable. Windows でthread_localは機能的には、Microsoft 固有_ _declspec (thread)属性。On Windows, thread_local is functionally equivalent to the Microsoft-specific __declspec( thread ) attribute.

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

について注意すべき点、thread_local指定子。Things to note about the thread_local specifier:

  • すべての呼び出し元スレッドを Dll に動的に初期化されたスレッド ローカル変数が正しく初期化されていません可能性があります。Dynamically initialized thread-local variables in DLLs may not be correctly initialized on all calling threads. 詳細については、スレッド に関するページを参照してください。For more information, see thread.

  • thread_local指定子と組み合わせることがあります静的またはexternします。The thread_local specifier may be combined with static or extern.

  • 適用できるthread_localのみにデータの宣言と定義されます。thread_local関数宣言または定義では使用できません。You can apply thread_local only to data declarations and definitions; thread_local cannot be used on function declarations or definitions.

  • thread_local は、静的ストレージ存続期間のあるデータ項目にのみ指定できます。You can specify thread_local only on data items with static storage duration. これには、グローバルなデータ オブジェクトが含まれます (どちらも静的extern)、ローカルな静的オブジェクト、およびクラスの静的データ メンバー。This includes global data objects (both static and extern), local static objects, and static data members of classes. 任意のローカル変数が宣言されているthread_localは他のストレージ クラスが提供されていない場合は、暗黙的に静的つまり、ブロック スコープでthread_localと等価thread_local staticします。Any local variable declared thread_local is implicitly static if no other storage class is provided; in other words, at block scope thread_local is equivalent to thread_local static.

  • 宣言と定義が同じファイルと別々のファイルのどちらで発生する場合でも、スレッド ローカル オブジェクトの宣言と定義には thread_local を使用する必要があります。You must specify thread_local for both the declaration and the definition of a thread local object, whether the declaration and definition occur in the same file or separate files.

Windows でthread_localは機能的に等価_declspecする点を除いて _declspec型定義に適用できるし、C コードでは無効です。On Windows, thread_local is functionally equivalent to __declspec(thread) except that __declspec(thread) can be applied to a type definition and is valid in C code. thread_local は C++ 標準の一部であり、移植性がより高いため、できるだけ常にこれを使用してください。Whenever possible, use thread_local because it is part of the C++ standard and is therefore more portable.

registerregister

Visual Studio 2017 バージョン 15.3 以降(で使用可能な/std:c + + 17)。登録キーワードがサポートされているストレージ クラスではなくなりました。Visual Studio 2017 version 15.3 and later (available with /std:c++17): The register keyword is no longer a supported storage class. キーワードは、将来使用するための標準でまだ予約されています。The keyword is still reserved in the standard for future use.

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

例: 自動の静的な初期化との比較Example: automatic vs. static initialization

ローカル自動オブジェクトまたは変数が、制御フローが定義に到達するたびに初期化されます。A local automatic object or variable is initialized every time the flow of control reaches its definition. ローカル静的オブジェクトまたは変数が、最初に制御フローが定義に到達すると初期化されます。A local static object or variable is initialized the first time the flow of control reaches its definition.

オブジェクトの初期化と破棄をログに記録するクラスを定義し、I1I2、および I3 の 3 つのオブジェクトを定義する、次の例を考えます。Consider the following example, which defines a class that logs initialization and destruction of objects and then defines three objects, I1, I2, and 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

この例は、方法とタイミングを示しますオブジェクトI1I2I3初期化されますが破棄されるとします。This example demonstrates how and when the objects I1, I2, and I3 are initialized and when they are destroyed.

プログラムに関する注意事項をいくつかの点があります。There are several points to note about the program:

  • 最初に、制御フローが I1I2 を定義しているブロックを終了すると、これらは自動的に破棄されます。First, I1 and I2 are automatically destroyed when the flow of control exits the block in which they are defined.

  • 次に、C++ では、ブロックの先頭でオブジェクトや変数を宣言する必要はありません。Second, in C++, it is not necessary to declare objects or variables at the beginning of a block. さらに、これらのオブジェクトは、制御フローが定義に到達した場合にのみ初期化されますFurthermore, these objects are initialized only when the flow of control reaches their definitions. (このような定義には、I2I3 などがあります)。出力は、これらがいつ初期化されるかを正確に示します。(I2 and I3 are examples of such definitions.) The output shows exactly when they are initialized.

  • 最後に、I3 などの静的ローカル変数は、プログラム実行中は値が保持されますが、プログラムが終了すると破棄されます。Finally, static local variables such as I3 retain their values for the duration of the program, but are destroyed as the program terminates.

関連項目See also

宣言と定義Declarations and Definitions