Zoeken…


Invoering

Opslagklasse-aanduidingen zijn trefwoorden die in aangiften kunnen worden gebruikt. Ze hebben geen invloed op het type aangifte, maar wijzigen doorgaans de manier waarop de entiteit wordt opgeslagen.

Opmerkingen

Er zijn zes opslagklasse-aanduidingen, hoewel niet alle in dezelfde taalversie: auto (tot C ++ 11), register (tot C ++ 17), static , thread_local (sinds C ++ 11), extern en mutable .

Volgens de norm

Er zal hoogstens één opslagklasse-specificatie verschijnen in een gegeven DEC-specificatie-seq, behalve dat thread_local kan verschijnen met static of extern .

Een aangifte mag geen specificatie voor opslagklasse bevatten. In dat geval geeft de taal een standaardgedrag aan. Standaard heeft bijvoorbeeld een variabele die bij blokbereik wordt gedeclareerd impliciet automatische opslagduur.

veranderlijk

Een specificatie die kan worden toegepast op de aangifte van een niet-statisch, niet-referentiegegevenslid van een klasse. Een veranderlijk lid van een klasse is geen const zelfs niet als het object 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

Een tweede betekenis voor mutable is toegevoegd in C ++ 11. Wanneer het de parameterlijst van een lambda volgt, onderdrukt het de impliciete const op de functieoproepoperator van de lambda. Daarom kan een veranderlijke lambda de waarden van entiteiten die zijn vastgelegd door kopiëren wijzigen. Zie veranderlijke lambdas voor meer informatie.

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

Merk op dat mutable geen specificatie van opslagklasse is wanneer het op deze manier wordt gebruikt om een mutable lambda te vormen.

registreren

C ++ 17

Een opslagklasse-aanduiding die de compiler aangeeft dat een variabele intensief zal worden gebruikt. Het woord "register" houdt verband met het feit dat een compiler ervoor zou kunnen kiezen om een dergelijke variabele in een CPU-register op te slaan, zodat deze in minder klokcycli toegankelijk is. Het werd afgeschaft vanaf C ++ 11.

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

Zowel lokale variabelen als functieparameters kunnen register worden verklaard. In tegenstelling tot C, legt C ++ geen beperkingen op aan wat kan worden gedaan met een register . Het is bijvoorbeeld geldig om het adres van een register te nemen, maar dit kan voorkomen dat de compiler zo'n variabele daadwerkelijk in een register opslaat.

C ++ 17

Het sleutelwoord register ongebruikt en gereserveerd. Een programma dat het zoekwoord gebruikt register is slecht gevormd.

statisch

De static opslagklasse-aanduiding heeft drie verschillende betekenissen.

  1. Geeft interne koppeling aan een variabele of functie die op naamruimtebereik is gedeclareerd.

    // 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. Declareert dat een variabele een statische opslagduur heeft (tenzij het thread_local ). Variabelen voor naamruimtebereik zijn impliciet statisch. Een statische lokale variabele wordt slechts eenmaal geïnitialiseerd, de eerste tijdcontrole doorloopt zijn definitie en wordt niet vernietigd telkens wanneer de scope wordt verlaten.

    void f() {
        static int count = 0;
        std::cout << "f has been called " << ++count << " times so far\n";
    }
    
  3. Wanneer toegepast op de verklaring van een lid van de klasse, verklaart dat lid een statisch lid .

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

Merk op dat in het geval van een lid met statische gegevens van een klasse, zowel 2 als 3 tegelijkertijd van toepassing zijn: het static trefwoord maakt van het lid zowel een statisch gegevenslid als een variabele met een statische opslagduur.

auto

C ++ 03

Declareert een variabele om automatische opslagduur te hebben. Het is overbodig, omdat automatische opslagduur al de standaard is bij block scope en de auto specifier niet is toegestaan bij namespace scope.

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

In C ++ 11 heeft auto de betekenis volledig gewijzigd en is niet langer een specificatie voor de opslagklasse, maar wordt in plaats daarvan gebruikt voor het aftrekken van het type .

extern

De extern opslagklasse- extern kan een aangifte op een van de volgende drie manieren wijzigen, afhankelijk van de context:

  1. Het kan worden gebruikt om een variabele te declareren zonder deze te definiëren. Meestal wordt dit gebruikt in een headerbestand voor een variabele die wordt gedefinieerd in een afzonderlijk implementatiebestand.

    // 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. Het geeft externe koppeling aan een variabele op naamruimtebereik, zelfs als const of constexpr anders een interne koppeling zou hebben veroorzaakt.

    // 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. Het herdefinieert een variabele op blokbereik als deze eerder met koppeling werd gedeclareerd. Anders declareert het een nieuwe variabele met koppeling, die lid is van de dichtstbijzijnde omringende naamruimte.

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

Een functie kan ook extern worden verklaard, maar dit heeft geen effect. Het wordt meestal gebruikt als een hint voor de lezer dat een hier aangegeven functie is gedefinieerd in een andere vertaaleenheid. Bijvoorbeeld:

 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

In de bovenstaande code, als f zou worden gewijzigd in extern en g in niet- extern , zou dit de correctheid of semantiek van het programma helemaal niet beïnvloeden, maar zou het waarschijnlijk de lezer van de code verwarren.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow