Ricerca…


introduzione

Gli identificatori delle classi di archiviazione sono parole chiave che possono essere utilizzate nelle dichiarazioni. Non influenzano il tipo della dichiarazione, ma in genere modificano il modo in cui l'entità è archiviata.

Osservazioni

Esistono sei identificatori di classe di memoria, sebbene non tutti nella stessa versione della lingua: auto (fino a C ++ 11), register (fino a C ++ 17), static , thread_local (dal C ++ 11), extern e mutable .

Secondo lo standard,

Al massimo un identificatore della classe di memoria deve apparire in un declinatore-se-specificatore seq, eccetto che thread_local può apparire con static o extern .

Una dichiarazione potrebbe non contenere alcun identificatore di classe di memoria. In tal caso, la lingua specifica un comportamento predefinito. Ad esempio, per impostazione predefinita, una variabile dichiarata a livello di blocco ha implicitamente durata di archiviazione automatica.

mutevole

Un identificatore che può essere applicato alla dichiarazione di un membro dati non statico e non di riferimento di una classe. Un membro mutabile di una classe non è const nemmeno quando l'oggetto è 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

Un secondo significato per mutable stato aggiunto in C ++ 11. Quando segue la lista dei parametri di un lambda, sopprime il const implicito sull'operatore di chiamata della funzione lambda. Pertanto, un lambda mutabile può modificare i valori delle entità catturate dalla copia. Vedi mutable lambda per maggiori dettagli.

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

Si noti che mutable non è uno specificatore della classe di memoria quando viene usato in questo modo per formare un lambda mutabile.

Registrare

C ++ 17

Un identificatore della classe di memoria che suggerisce al compilatore che una variabile sarà usata pesantemente. La parola "registro" è legata al fatto che un compilatore potrebbe scegliere di memorizzare tale variabile in un registro della CPU in modo che sia accessibile in un numero inferiore di cicli di clock. È stato deprecato a partire da C ++ 11.

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

Sia le variabili locali che i parametri di funzione possono essere dichiarati register . A differenza di C, C ++ non pone alcuna restrizione su cosa può essere fatto con una variabile di register . Ad esempio, è valido prendere l'indirizzo di una variabile di register , ma ciò potrebbe impedire al compilatore di memorizzare effettivamente tale variabile in un registro.

C ++ 17

Il register parole chiave non è utilizzato e riservato. Un programma che utilizza il register parole chiave è mal formato.

statico

Lo specificatore della classe di archiviazione static ha tre diversi significati.

  1. Fornisce il collegamento interno a una variabile o funzione dichiarata nell'ambito dello spazio dei nomi.

    // 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. Dichiara una variabile con durata di memorizzazione statica (a meno che non sia thread_local ). Le variabili nell'ambito dello spazio dei nomi sono implicitamente statiche. Una variabile locale statica viene inizializzata solo una volta, il primo controllo del tempo passa attraverso la sua definizione e non viene distrutta ogni volta che si esce dall'ambito.

    void f() {
        static int count = 0;
        std::cout << "f has been called " << ++count << " times so far\n";
    }
    
  3. Quando viene applicato alla dichiarazione di un membro della classe, dichiara che il membro deve essere un membro statico .

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

Si noti che nel caso di un membro di dati statici di una classe, entrambi 2 e 3 si applicano contemporaneamente: la parola chiave static fa sia il membro in un membro di dati statici che lo trasforma in una variabile con durata di archiviazione statica.

auto

C ++ 03

Dichiara una variabile con durata della memorizzazione automatica. È ridondante, poiché la durata della memorizzazione automatica è già l'impostazione predefinita nell'ambito del blocco e l'identificatore automatico non è consentito nello spazio dei nomi.

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, l' auto cambiato completamente il significato e non è più un identificatore della classe di memoria, ma viene invece utilizzato per la deduzione del tipo .

extern

L' extern classe di archiviazione extern può modificare una dichiarazione in uno dei tre modi seguenti, a seconda del contesto:

  1. Può essere usato per dichiarare una variabile senza definirla. In genere, questo viene utilizzato in un file di intestazione per una variabile che verrà definita in un file di implementazione separato.

    // 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. Fornisce il collegamento esterno a una variabile in ambito namespace anche se const o constexpr avrebbero altrimenti causato un collegamento interno.

    // 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. Ricalcola una variabile a livello di blocco se precedentemente dichiarata con linkage. Altrimenti, dichiara una nuova variabile con linkage, che è un membro del più vicino spazio dei nomi.

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

Una funzione può anche essere dichiarata extern , ma ciò non ha alcun effetto. Solitamente viene usato come suggerimento per il lettore che una funzione dichiarata qui è definita in un'altra unità di traduzione. Per esempio:

 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

Nel codice precedente, se f stato cambiato in extern e g in non- extern , non influenzerebbe affatto la correttezza o la semantica del programma, ma probabilmente confonderebbe il lettore del codice.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow