수색…


소개

저장소 클래스 지정자는 선언에 사용할 수있는 키워드 입니다. 선언의 유형에는 영향을주지 않지만 일반적으로 엔티티가 저장되는 방식을 수정합니다.

비고

auto (C ++ 11까지), register (C ++ 17까지), static , thread_local (C ++ 11 이후), extern , and의 6 가지 저장소 클래스 지정 auto 있습니다. mutable 있습니다.

표준에 따르면,

최대 하나의 저장 클래스 지정 자는 주어진 decl-specifier-seq에 나타나야한다. 단 thread_localstatic 또는 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;
    }
};
C ++ 11

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 은 변경 가능한 람다를 형성하기 위해이 방법을 사용할 때 저장 클래스 지정자가 아닙니다 .

레지스터

C ++ 17

변수가 많이 사용될 것임을 컴파일러에 알리는 저장소 클래스 지정자입니다. "레지스터"라는 단어는 컴파일러가 이러한 변수를 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 변수의 주소를 가져 오는 것은 유효하지만 컴파일러가 이러한 변수를 실제로 레지스터에 저장하는 것을 방해 할 수 있습니다.

C ++ 17

키워드 register 가 사용되지 않고 예약되어 있습니다. 키워드 register 를 사용하는 프로그램이 잘못되었습니다.

공전

static 저장소 클래스 지정자에는 세 가지 의미가 있습니다.

  1. 네임 스페이스 범위에서 선언 된 변수 또는 함수에 내부 연결을 부여합니다.

    // 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));
    }
    
  2. 정적 저장 기간을 갖도록 변수를 선언합니다 ( thread_local 이 아닌 경우). 네임 스페이스 범위 변수는 암시 적으로 정적입니다. 정적 로컬 변수는 처음으로 한 번만 초기화되고 처음 컨트롤은 해당 정의를 통과하며 범위가 종료 될 때마다 제거되지 않습니다.

    void f() {
        static int count = 0;
        std::cout << "f has been called " << ++count << " times so far\n";
    }
    
  3. 클래스 멤버의 선언에 적용되면 해당 멤버를 정적 멤버 로 선언합니다.

    struct S {
        static S* create() {
            return new S;
        }
    };
    int main() {
        S* s = S::create();
    }
    

클래스의 정적 데이터 멤버의 경우 2와 3 모두 동시에 적용됩니다. static 키워드는 멤버를 정적 데이터 멤버로 만들고 정적 저장 기간이있는 변수로 만듭니다.

자동

C ++ 03

자동 저장 기간을 갖도록 변수를 선언합니다. 자동 저장 기간은 이미 블록 범위에서 기본값이므로 네임 스페이스 범위에서 자동 지정자가 허용되지 않으므로 중복됩니다.

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 스토리지 클래스 지정자는 컨텍스트에 따라 다음 세 가지 방법 중 하나를 사용하여 선언을 수정할 수 있습니다.

  1. 변수를 정의하지 않고 선언하는 데 사용할 수 있습니다. 일반적으로 이것은 별도의 구현 파일에 정의 될 변수의 헤더 파일에 사용됩니다.

    // 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)
    
  2. constconstexpr 이 내부 연결을 야기 할지라도 네임 스페이스 범위에서 변수에 대한 외부 연결을 제공합니다.

    // 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
    }
    
  3. 이전에 링크로 선언 된 경우 블록 범위에서 변수를 다시 선언합니다. 그렇지 않으면 가장 가까운 둘러싸는 네임 스페이스의 구성원 인 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

위의 코드에서 fextern 로 변경되고 gextern 이 아닌 것으로 변경되면 프로그램의 정확성이나 의미에 전혀 영향을 미치지 않지만 코드 독자를 혼동시킬 수 있습니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow