C++ 변수 선언 컨텍스트의 스토리지 클래스는 개체의 수명, 연결 및 메모리 위치를 제어하는 형식 지정자입니다. 주어진 개체에는 스토리지 클래스가 하나만 있을 수 있습니다. 블록 내에 정의된 변수에는 , 또는 thread_local
지정자를 사용하여 지정하지 않는 한 자동 스토리지가 extern
static
있습니다. 자동 개체 및 변수에는 연결이 없습니다. 블록 외부의 코드에는 표시되지 않습니다. 실행이 블록에 들어갈 때 메모리가 자동으로 할당되고 블록이 종료되면 할당이 해제됩니다.
주의
키워드는
mutable
스토리지 클래스 지정자로 간주될 수 있습니다. 그러나 클래스 정의의 멤버 목록에서만 사용할 수 있습니다.Visual Studio 2010 이상: 키워드는
auto
더 이상 C++ 스토리지 클래스 지정자가 아니고register
키워드는 더 이상 사용되지 않습니다. Visual Studio 2017 버전 15.7 이상: (모드 이상에서/std:c++17
사용 가능):register
키워드가 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
사용하여 전역 범위, 네임스페이스 범위 및 클래스 범위에서 변수 및 함수를 선언할 수 있습니다. 정적 변수는 로컬 범위에서 선언할 수도 있습니다.
정적 생존 기간이란 프로그램이 시작될 때 개체 또는 변수가 할당되고 프로그램이 끝날 때 개체 또는 변수가 할당 취소됨을 의미합니다. 외부 연결은 변수의 이름이 변수가 선언된 파일 외부에서 볼 수 있음을 의미합니다. 반대로 내부 링크는 변수가 선언된 파일 외부에 이름이 표시되지 않음을 의미합니다. 기본적으로 전역 네임스페이스에서 정의된 개체 또는 변수에는 정적 지속 기간 및 외부 링크가 있습니다. 키워드는 static
다음과 같은 경우에 사용할 수 있습니다.
파일 범위(전역 및/또는 네임스페이스 범위)
static
에서 변수 또는 함수를 선언하는 경우 키워드는 변수 또는 함수에 내부 링크가 있음을 지정합니다. 변수를 선언할 때 변수가 정적 생존 기간을 가지며, 다른 값을 지정하지 않으면 컴파일러가 0으로 초기화합니다.함수에서 변수를 선언할 때 키워드는 해당 함수
static
에 대한 호출 간에 변수의 상태를 유지하도록 지정합니다.클래스 선언에서 데이터 멤버를 선언
static
할 때 키워드는 클래스의 모든 인스턴스에서 하나의 멤버 복사본을 공유한다고 지정합니다. 데이터 멤버는static
파일 범위에서 정의해야 합니다. 이니셜라이저를 가질 수 있는 것으로const static
선언하는 정수 데이터 멤버입니다.클래스 선언에서 멤버 함수를 선언
static
할 때 키워드는 함수가 클래스의 모든 인스턴스에서 공유되도록 지정합니다. 함수에static
암시적this
포인터가 없으므로 멤버 함수는 인스턴스 멤버에 액세스할 수 없습니다. 인스턴스 멤버에 액세스하려면 인스턴스 포인터 또는 참조인 매개 변수를 사용하여 함수를 선언합니다.의 멤버
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
더 이상 지원되는 스토리지 클래스가 아닙니다. 해당 용도로 인해 진단이 발생합니다. 키워드는 나중에 사용할 수 있는 표준에 계속 예약되어 있습니다.
register int val; // warning C5033: 'register' is no longer a supported storage class
예: 자동 및 정적 초기화
로컬 자동 개체나 변수는 컨트롤의 흐름이 정의에 도달할 때마다 초기화됩니다. 로컬 정적 개체 또는 변수는 컨트롤의 흐름이 정의에 처음 도달할 때 초기화됩니다.
다음 예제에서는 개체의 초기화 및 개체의 초기화와 소멸을 기록한 후 I1
, I2
및 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
이 예제에서는 개체I1
I2
가 초기화되는 방법과 시기 및 I3
제거 시기를 보여 줍니다.
프로그램에 대해 주의해야 할 몇 가지 사항이 있습니다.
먼저 제어
I1
I2
흐름이 정의된 블록을 종료하면 자동으로 제거됩니다.둘째, C++에서는 블록의 시작 부분에 개체 또는 변수를 선언할 필요가 없습니다. 또한 제어 흐름이 정의에 도달해야 이 개체가 초기화됩니다. (
I2
및I3
이러한 정의의 예입니다.) 출력은 초기화되는 시기를 정확하게 표시합니다.마지막으로, 프로그램이 실행되는 동안 해당 값을 유지하지만 프로그램이 종료되면 소멸되는 정
I3
적 지역 변수입니다.