스토리지 클래스
C++ 변수 선언 컨텍스트의 스토리지 클래스는 개체의 수명, 연결 및 메모리 위치를 제어하는 형식 지정자입니다. 주어진 개체에는 스토리지 클래스가 하나만 있을 수 있습니다. 블록 내에 정의된 변수에는 , 또는 thread_local
지정자를 사용하여 지정하지 않는 한 자동 스토리지가 extern
static
있습니다. 자동 개체 및 변수에는 연결이 없습니다. 블록 외부의 코드에는 표시되지 않습니다. 실행이 블록에 들어갈 때 메모리가 자동으로 할당되고 블록이 종료되면 할당이 해제됩니다.
주의
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) 다음과 같은 경우에 사용할 수 있습니다.
파일 범위(전역 및/또는 네임스페이스 범위)
static
에서 변수 또는 함수를 선언하는 경우 키워드(keyword) 변수 또는 함수에 내부 링크가 있음을 지정합니다. 변수를 선언할 때 변수가 정적 생존 기간을 가지며, 다른 값을 지정하지 않으면 컴파일러가 0으로 초기화합니다.함수
static
에서 변수를 선언할 때 키워드(keyword) 변수가 해당 함수에 대한 호출 간의 상태를 유지하도록 지정합니다.클래스 선언
static
에서 데이터 멤버를 선언하는 경우 키워드(keyword) 클래스의 모든 인스턴스에서 하나의 멤버 복사본을 공유되도록 지정합니다. 데이터 멤버는static
파일 범위에서 정의해야 합니다. 이니셜라이저를 가질 수 있는 것으로const static
선언하는 정수 데이터 멤버입니다.클래스 선언에서 멤버 함수를 선언
static
할 때 키워드(keyword) 클래스의 모든 인스턴스에서 함수를 공유되도록 지정합니다. 함수에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
키워드(keyword) 더 이상 지원되는 스토리지 클래스가 아닙니다. 해당 용도로 인해 진단이 발생합니다. 키워드(keyword) 향후 사용을 위해 여전히 표준으로 예약되어 있습니다.
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
적 지역 변수입니다.
참고 항목
피드백
https://aka.ms/ContentUserFeedback
출시 예정: 2024년 내내 콘텐츠에 대한 피드백 메커니즘으로 GitHub 문제를 단계적으로 폐지하고 이를 새로운 피드백 시스템으로 바꿀 예정입니다. 자세한 내용은 다음을 참조하세요.다음에 대한 사용자 의견 제출 및 보기