Sök…


Introduktion

Lagringsklassspecifikationer är nyckelord som kan användas i deklarationer. De påverkar inte typ av deklaration, men ändrar vanligtvis sättet på vilket enheten lagras.

Anmärkningar

Det finns sex lagringsklassspecifikationer, även om inte alla i samma version av språket: auto (tills C ++ 11), register (tills C ++ 17), static , thread_local (sedan C ++ 11), extern och mutable .

Enligt standarden

Högst en lagerklass-specifikatör ska visas i en given decl-specificier-seq, förutom att thread_local kan visas med static eller extern .

En deklaration får inte innehålla någon specifikation för lagringsklass. I så fall anger språket ett standardbeteende. Till exempel har en variabel som deklarerats till blockomfång implicit automatisk lagringsvaraktighet.

föränderlig

En specifikator som kan tillämpas på deklarationen av en icke-statisk, icke-referensdatamedlem i en klass. En föränderlig medlem i en klass är inte const även när objektet är 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

En andra betydelse för mutable tillsattes i C ++ 11. När den följer parameterlistan för en lambda undertrycker den implicit const på lambdas funktionssamtaloperatör. Därför kan en muterbar lambda modifiera värdena på enheter som fångats med kopia. Se muterbara lambdor för mer information.

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;
}

Observera att mutable inte är en lagringsklassspecifikator när det används på detta sätt för att bilda en mutbar lambda.

Registrera

C ++ 17

En lagringsklassspecifikation som antyder för kompilatorn att en variabel kommer att användas kraftigt. Ordet "register" är relaterat till det faktum att en kompilator kan välja att lagra en sådan variabel i ett CPU-register så att det kan nås i färre klockcykler. Det avskrivs med början i C ++ 11.

register int i = 0;
while (i < 100) {
    f(i);
    int g = i*i;
    i += h(i, g);
}

Både lokala variabler och funktionsparametrar kan förklaras register . Till skillnad från C sätter C ++ inte några begränsningar för vad som kan göras med en register . Till exempel är det giltigt att ta adressen till en register , men detta kan förhindra att kompilatorn faktiskt lagrar en sådan variabel i ett register.

C ++ 17

Nyckelordet register är oanvänd och reserverade. Ett program som använder sökordet register är illa bildas.

statisk

Den static lagringsklassspecifikationen har tre olika betydelser.

  1. Ger intern länk till en variabel eller funktion som deklareras inom namnområdet.

    // 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. Förklarar att en variabel ska ha statisk lagringsvaraktighet (såvida den inte är thread_local ). Variabler för namnutrymme är implicit statiska. En statisk lokal variabel initialiseras endast en gång, den första gången kontrollen passerar sin definition och förstörs inte varje gång dess omfattning lämnas.

    void f() {
        static int count = 0;
        std::cout << "f has been called " << ++count << " times so far\n";
    }
    
  3. När den tillämpas på en klassmedlemmars förklaring förklarar den medlemmen att vara en statisk medlem .

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

Observera att när det gäller en statisk datamedlem i en klass gäller både 2 och 3 samtidigt: det static nyckelordet båda gör medlemmet till ett statiskt datamedlem och gör det till en variabel med statisk lagringsvaraktighet.

bil

C ++ 03

Förklarar en variabel för att ha automatisk lagringstid. Det är överflödigt, eftersom automatisk lagringsvaraktighet redan är standard vid blockomfång, och autospecifikationen är inte tillåten i namnområdet.

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

I C ++ 11 ändrade auto betydelsen fullständigt och är inte längre en specifikation för lagringsklass utan används istället för typavdrag .

extern

Den extern lagringsklassspecifikationen kan modifiera en deklaration på ett av de tre följande sätten, beroende på sammanhang:

  1. Den kan användas för att deklarera en variabel utan att definiera den. Vanligtvis används detta i en rubrikfil för en variabel som kommer att definieras i en separat implementeringsfil.

    // 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. Det ger extern länk till en variabel i namnutrymmet, även om const eller constexpr annars skulle ha orsakat att den har intern länk.

    // 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. Den omklassificerar en variabel vid blockomfång om den tidigare förklarats med koppling. Annars förklarar den en ny variabel med koppling, som är medlem i närmaste bifogade namnutrymme.

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

En funktion kan också förklaras extern , men detta har ingen effekt. Det används vanligtvis som ett tips för läsaren att en funktion som deklareras här definieras i en annan översättningsenhet. Till exempel:

 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

I koden ovan, om f ändrades till extern och g till icke- extern , skulle det inte påverka programmets korrekthet eller semantik alls, men det kan troligen förvirra läsaren av koden.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow