C++
저장소 클래스 지정자
수색…
소개
저장소 클래스 지정자는 선언에 사용할 수있는 키워드 입니다. 선언의 유형에는 영향을주지 않지만 일반적으로 엔티티가 저장되는 방식을 수정합니다.
비고
auto
(C ++ 11까지), register
(C ++ 17까지), static
, thread_local
(C ++ 11 이후), extern
, and의 6 가지 저장소 클래스 지정 auto
있습니다. mutable
있습니다.
표준에 따르면,
최대 하나의 저장 클래스 지정 자는 주어진 decl-specifier-seq에 나타나야한다. 단
thread_local
은static
또는extern
나타날 수있다.
선언은 스토리지 클래스 지정자를 포함 할 수 없습니다. 이 경우 언어는 기본 동작을 지정합니다. 예를 들어 기본적으로 블록 범위에서 선언 된 변수에는 암시 적으로 자동 저장 기간이 있습니다.
변하기 쉬운
클래스의 비 정적, 비 참조 데이터 멤버의 선언에 적용 할 수있는 지정자입니다. 객체가 const
경우에도 클래스의 변경 가능한 멤버는 const
가 아닙니다.
class C {
int x;
mutable int times_accessed;
public:
C(): x(0), times_accessed(0) {
}
int get_x() const {
++times_accessed; // ok: const member function can modify mutable data member
return x;
}
void set_x(int x) {
++times_accessed;
this->x = x;
}
};
mutable
에 대한 두 번째 의미가 C ++ 11에 추가되었습니다. 람다의 매개 변수 목록을 const
때, 람다의 함수 호출 연산자에 대한 암시 적 const
를 억제합니다. 따라서, 변경 가능한 람다는 copy에 의해 캡쳐 된 엔티티의 값을 수정할 수 있습니다. 자세한 내용은 가변 람다 (lambda) 를 참조하십시오.
std::vector<int> my_iota(int start, int count) {
std::vector<int> result(count);
std::generate(result.begin(), result.end(),
[start]() mutable { return start++; });
return result;
}
mutable
은 변경 가능한 람다를 형성하기 위해이 방법을 사용할 때 저장 클래스 지정자가 아닙니다 .
레지스터
변수가 많이 사용될 것임을 컴파일러에 알리는 저장소 클래스 지정자입니다. "레지스터"라는 단어는 컴파일러가 이러한 변수를 CPU 레지스터에 저장하여 적은 클럭 사이클에서 액세스 할 수 있도록하는 것과 관련이 있습니다. C ++ 11부터는 사용되지 않습니다.
register int i = 0;
while (i < 100) {
f(i);
int g = i*i;
i += h(i, g);
}
지역 변수와 함수 매개 변수는 모두 register
로 선언 될 수 있습니다. C와 달리 C ++은 register
변수로 수행 할 수있는 것에 대한 어떠한 제한도 가하지 않습니다. 예를 들어 register
변수의 주소를 가져 오는 것은 유효하지만 컴파일러가 이러한 변수를 실제로 레지스터에 저장하는 것을 방해 할 수 있습니다.
키워드 register
가 사용되지 않고 예약되어 있습니다. 키워드 register
를 사용하는 프로그램이 잘못되었습니다.
공전
static
저장소 클래스 지정자에는 세 가지 의미가 있습니다.
네임 스페이스 범위에서 선언 된 변수 또는 함수에 내부 연결을 부여합니다.
// internal function; can't be linked to static double semiperimeter(double a, double b, double c) { return (a + b + c)/2.0; } // exported to client double area(double a, double b, double c) { const double s = semiperimeter(a, b, c); return sqrt(s*(s-a)*(s-b)*(s-c)); }
정적 저장 기간을 갖도록 변수를 선언합니다 (
thread_local
이 아닌 경우). 네임 스페이스 범위 변수는 암시 적으로 정적입니다. 정적 로컬 변수는 처음으로 한 번만 초기화되고 처음 컨트롤은 해당 정의를 통과하며 범위가 종료 될 때마다 제거되지 않습니다.void f() { static int count = 0; std::cout << "f has been called " << ++count << " times so far\n"; }
클래스 멤버의 선언에 적용되면 해당 멤버를 정적 멤버 로 선언합니다.
struct S { static S* create() { return new S; } }; int main() { S* s = S::create(); }
클래스의 정적 데이터 멤버의 경우 2와 3 모두 동시에 적용됩니다. static
키워드는 멤버를 정적 데이터 멤버로 만들고 정적 저장 기간이있는 변수로 만듭니다.
자동
자동 저장 기간을 갖도록 변수를 선언합니다. 자동 저장 기간은 이미 블록 범위에서 기본값이므로 네임 스페이스 범위에서 자동 지정자가 허용되지 않으므로 중복됩니다.
void f() {
auto int x; // equivalent to: int x;
auto y; // illegal in C++; legal in C89
}
auto int z; // illegal: namespace-scope variable cannot be automatic
C ++ 11에서는 auto
가 의미를 완전히 변경했으며 더 이상 저장소 클래스 지정자가 아니며 대신 형식 공제에 사용됩니다.
통근자
extern
스토리지 클래스 지정자는 컨텍스트에 따라 다음 세 가지 방법 중 하나를 사용하여 선언을 수정할 수 있습니다.
변수를 정의하지 않고 선언하는 데 사용할 수 있습니다. 일반적으로 이것은 별도의 구현 파일에 정의 될 변수의 헤더 파일에 사용됩니다.
// global scope int x; // definition; x will be default-initialized extern int y; // declaration; y is defined elsewhere, most likely another TU extern int z = 42; // definition; "extern" has no effect here (compiler may warn)
const
나constexpr
이 내부 연결을 야기 할지라도 네임 스페이스 범위에서 변수에 대한 외부 연결을 제공합니다.// global scope const int w = 42; // internal linkage in C++; external linkage in C static const int x = 42; // internal linkage in both C++ and C extern const int y = 42; // external linkage in both C++ and C namespace { extern const int z = 42; // however, this has internal linkage since // it's in an unnamed namespace }
이전에 링크로 선언 된 경우 블록 범위에서 변수를 다시 선언합니다. 그렇지 않으면 가장 가까운 둘러싸는 네임 스페이스의 구성원 인 linkage를 사용하여 새 변수를 선언합니다.
// global scope namespace { int x = 1; struct C { int x = 2; void f() { extern int x; // redeclares namespace-scope x std::cout << x << '\n'; // therefore, this prints 1, not 2 } }; } void g() { extern int y; // y has external linkage; refers to global y defined elsewhere }
함수는 extern
으로 선언 할 수도 있지만 아무 효과가 없습니다. 일반적으로 여기에 선언 된 함수가 다른 번역 단위에서 정의된다는 것을 독자에게 힌트로 사용합니다. 예 :
void f(); // typically a forward declaration; f defined later in this TU
extern void g(); // typically not a forward declaration; g defined in another TU
위의 코드에서 f
가 extern
로 변경되고 g
가 extern
이 아닌 것으로 변경되면 프로그램의 정확성이나 의미에 전혀 영향을 미치지 않지만 코드 독자를 혼동시킬 수 있습니다.