스토리지 클래스

C++ 변수 선언 컨텍스트의 스토리지 클래스는 개체의 수명, 연결 및 메모리 위치를 제어하는 형식 지정자입니다. 주어진 개체에는 스토리지 클래스가 하나만 있을 수 있습니다. 블록 내에 정의된 변수에는 , 또는 thread_local 지정자를 사용하여 지정하지 않는 한 자동 스토리지가 externstatic있습니다. 자동 개체 및 변수에는 연결이 없습니다. 블록 외부의 코드에는 표시되지 않습니다. 실행이 블록에 들어갈 때 메모리가 자동으로 할당되고 블록이 종료되면 할당이 해제됩니다.

주의

  • mutable 키워드(keyword) 스토리지 클래스 지정자로 간주될 수 있습니다. 그러나 클래스 정의의 멤버 목록에서만 사용할 수 있습니다.

  • Visual Studio 2010 이상:auto 키워드(keyword) 더 이상 C++ 스토리지 클래스 지정자가 아니고 register 키워드(keyword) 더 이상 사용되지 않습니다. Visual Studio 2017 버전 15.7 이상: (모드 이상에서 /std:c++17 사용 가능): register 키워드(keyword) C++ 언어에서 제거됩니다. 이 기능을 사용하면 진단 메시지가 발생합니다.

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

static 키워드(keyword) 사용하여 전역 범위, 네임스페이스 범위 및 클래스 범위에서 변수 및 함수를 선언할 수 있습니다. 정적 변수는 로컬 범위에서 선언할 수도 있습니다.

정적 생존 기간이란 프로그램이 시작될 때 개체 또는 변수가 할당되고 프로그램이 끝날 때 개체 또는 변수가 할당 취소됨을 의미합니다. 외부 연결은 변수의 이름이 변수가 선언된 파일 외부에서 볼 수 있음을 의미합니다. 반대로 내부 링크는 변수가 선언된 파일 외부에 이름이 표시되지 않음을 의미합니다. 기본적으로 전역 네임스페이스에서 정의된 개체 또는 변수에는 정적 지속 기간 및 외부 링크가 있습니다. static 키워드(keyword) 다음과 같은 경우에 사용할 수 있습니다.

  1. 파일 범위(전역 및/또는 네임스페이스 범위)static에서 변수 또는 함수를 선언하는 경우 키워드(keyword) 변수 또는 함수에 내부 링크가 있음을 지정합니다. 변수를 선언할 때 변수가 정적 생존 기간을 가지며, 다른 값을 지정하지 않으면 컴파일러가 0으로 초기화합니다.

  2. 함수 static 에서 변수를 선언할 때 키워드(keyword) 변수가 해당 함수에 대한 호출 간의 상태를 유지하도록 지정합니다.

  3. 클래스 선언 static 에서 데이터 멤버를 선언하는 경우 키워드(keyword) 클래스의 모든 인스턴스에서 하나의 멤버 복사본을 공유되도록 지정합니다. 데이터 멤버는 static 파일 범위에서 정의해야 합니다. 이니셜라이저를 가질 수 있는 것으로 const static 선언하는 정수 데이터 멤버입니다.

  4. 클래스 선언에서 멤버 함수를 선언 static 할 때 키워드(keyword) 클래스의 모든 인스턴스에서 함수를 공유되도록 지정합니다. 함수에 static 암시적 this 포인터가 없으므로 멤버 함수는 인스턴스 멤버에 액세스할 수 없습니다. 인스턴스 멤버에 액세스하려면 인스턴스 포인터 또는 참조인 매개 변수를 사용하여 함수를 선언합니다.

  5. 의 멤버 union 를 선언 static할 수 없습니다. 그러나 전역적으로 선언된 익명 union 을 명시적으로 선언 static해야 합니다.

이 예제에서는 함수에 선언된 static 변수가 해당 함수에 대한 호출 간에 상태를 유지하는 방법을 보여 줍니다.

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

이 예제에서는 클래스에서의 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

다음 예제에서는 멤버 함수에 선언된 static 지역 변수를 보여줍니다. 변수는 static 전체 프로그램에서 사용할 수 있습니다. 형식의 모든 인스턴스는 변수의 동일한 복사본을 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

C++11 static 부터는 로컬 변수 초기화가 스레드로부터 안전합니다. 이 기능을 매직 정적이라고 도 합니다. 그러나 다중 스레드 애플리케이션에서는 모든 후속 할당을 동기화해야 합니다. CRT에 대한 종속성을 사용하지 않도록 플래그를 /Zc:threadSafeInit- 사용하여 스레드로부터 안전한 정적 초기화 기능을 사용하지 않도록 설정할 수 있습니다.

extern

선언된 extern 개체 및 변수는 다른 변환 단위 또는 묶은 범위에 외부 링크가 있는 것으로 정의된 개체를 선언합니다. 자세한 내용은 번역 단위 및 연결을 참조 extern 하세요.

thread_local (C++11)

지정자를 사용하여 thread_local 선언된 변수는 생성된 스레드에서만 액세스할 수 있습니다. 이 변수는 스레드를 만들 때 만들어지고 스레드가 제거될 때 제거됩니다. 각 스레드에 변수의 자체 복사본이 있습니다. Windows에서는 thread_local Microsoft 특정 __declspec( thread ) 특성과 기능적으로 동일합니다.

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 해야 할 사항:

  • DLL에서 동적으로 초기화된 스레드-로컬 변수는 모든 호출 스레드에서 올바르게 초기화되지 않을 수 있습니다. 자세한 내용은 thread를 참조하세요.

  • thread_local 지정자를 사용하거나 extern.와 결합 static 할 수 있습니다.

  • 데이터 선언 및 정의 thread_local 에만 적용 thread_local 할 수 있으며 함수 선언 또는 정의에는 사용할 수 없습니다.

  • 전역 데이터 개체(및 static ), 로컬 정적 개체 및 extern클래스의 정적 데이터 멤버를 포함하는 정적 스토리지 기간이 있는 데이터 항목에서만 지정할 thread_local 수 있습니다. 선언된 thread_local 모든 지역 변수는 다른 스토리지 클래스가 제공되지 않은 경우 암시적으로 정적입니다. 즉, 블록 범위 thread_local 에서 해당합니다 thread_local static.

  • 스레드 로컬 개체의 선언과 정의가 같은 파일에서 발생하는지, 아니면 별도의 파일에서 발생하는지와 관계없이 해당 선언과 정의 둘 다에 대해 thread_local을 지정해야 합니다.

  • 와 함께 std::launch::async변수를 사용하지 thread_local 않는 것이 좋습니다. 자세한 내용은 함수를 참조 <future> 하세요.

Windows에서는 thread_local * 형식 정의에 __declspec(thread) 적용할 수 있으며 C 코드에서 유효하다 *__declspec(thread)는 점을 제외하면 기능적으로 동일합니다. 가능하면 C++ 표준의 일부이므로 더 이식성이 높기 때문에 사용 thread_local 하세요.

register

Visual Studio 2017 버전 15.3 이상(모드 이상에서 /std:c++17 사용 가능): register 키워드(keyword) 더 이상 지원되는 스토리지 클래스가 아닙니다. 해당 용도로 인해 진단이 발생합니다. 키워드(keyword) 향후 사용을 위해 여전히 표준으로 예약되어 있습니다.

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

예: 자동 및 정적 초기화

로컬 자동 개체나 변수는 컨트롤의 흐름이 정의에 도달할 때마다 초기화됩니다. 로컬 정적 개체 또는 변수는 컨트롤의 흐름이 정의에 처음 도달할 때 초기화됩니다.

다음 예제에서는 개체의 초기화 및 개체의 초기화와 소멸을 기록한 후 I1, 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

이 예제에서는 개체I1I2가 초기화되는 방법과 시기 및 I3 제거 시기를 보여 줍니다.

프로그램에 대해 주의해야 할 몇 가지 사항이 있습니다.

  • 먼저 제어 I1I2 흐름이 정의된 블록을 종료하면 자동으로 제거됩니다.

  • 둘째, C++에서는 블록의 시작 부분에 개체 또는 변수를 선언할 필요가 없습니다. 또한 제어 흐름이 정의에 도달해야 이 개체가 초기화됩니다. (I2I3 이러한 정의의 예입니다.) 출력은 초기화되는 시기를 정확하게 표시합니다.

  • 마지막으로, 프로그램이 실행되는 동안 해당 값을 유지하지만 프로그램이 종료되면 소멸되는 정 I3 적 지역 변수입니다.

참고 항목

선언 및 정의