Pojęcia zakresu, czasu trwania i powiązań powodują wiele zamieszania, dlatego poświęcimy dodatkową lekcję, aby wszystko podsumować. Niektórych z tych rzeczy jeszcze nie omówiliśmy i są one tutaj tylko dla uzupełnienia/odniesienia później.
Podsumowanie zakresu
Identyfikator zakres określa, gdzie w kodzie źródłowym można uzyskać dostęp do identyfikatora.
- Zmienne o zakresie blokowym (lokalnym) można uzyskać dostęp tylko od momentu deklaracji do końca bloku, w którym są zadeklarowane (w tym zagnieżdżone bloki). Obejmuje to:
- Zmienne lokalne
- Parametry funkcji
- Definicje typów zdefiniowanych w programie (takie jak wyliczenia i klasy) zadeklarowane wewnątrz bloku
- Dostęp do zmiennych i funkcji za pomocą zasięgiem globalnym można uzyskać od momentu deklaracji aż do końca pliku. Obejmuje to:
- Zmienne globalne
- Funkcje
- Definicje typów zdefiniowanych przez program (takie jak wyliczenia i klasy) zadeklarowane w przestrzeni nazw lub w zasięgu globalnym
Podsumowanie czasu trwania
Przechowywanie zmiennej czasu trwania określa, kiedy jest on tworzony i niszczony.
- Zmienne o automatycznym Duration są tworzone w momencie definicji i niszczone po wyjściu z bloku, którego są częścią. Obejmuje to:
- Zmienne lokalne
- Parametry funkcji
- Zmienne o czas statyczny są tworzone podczas uruchamiania programu i niszczone po zakończeniu programu. Obejmuje to:
- Zmienne globalne
- Statyczne zmienne lokalne
- Zmienne o dynamicznym czasie trwania są tworzone i niszczone na żądanie programisty. Obejmuje to:
- Dynamicznie przydzielane zmienne
Podsumowanie powiązań
Identyfikator połączenie określa, czy deklaracja tego samego identyfikatora w innym zakresie odnosi się do tej samej jednostki (obiektu, funkcji, odniesienia itp.) czy nie.
Zmienne lokalne nie mają powiązania. Każda deklaracja identyfikatora bez powiązania odnosi się do unikalnego obiektu lub funkcji.
- Identyfikator z brak powiązania oznacza, że kolejna deklaracja tego samego identyfikatora odnosi się do unikalnej jednostki. Jednostki, których identyfikatory nie mają powiązania, obejmują:
- Zmienne lokalne
- Zdefiniowane przez program identyfikatory typów (takie jak wyliczenia i klasy) zadeklarowane wewnątrz bloku
- Identyfikator z powiązanie wewnętrzne oznaczają deklarację tego samego identyfikatora w tej samej jednostce translacji, która odnosi się do tego samego obiektu lub funkcji. Do jednostek, których identyfikatory mają wewnętrzne powiązanie, zaliczają się:
- Statyczne zmienne globalne (zainicjowane lub niezainicjowane)
- Funkcje statyczne
- Stałe zmienne globalne
- Nienazwane przestrzenie nazw i wszystko, co jest w nich zdefiniowane
- Identyfikator z powiązanie zewnętrzne oznacza deklarację tego samego identyfikatora w całym programie, odnoszącą się do tego samego obiektu lub funkcji. Jednostki, których identyfikatory mają zewnętrzne powiązanie obejmują:
- Funkcje niestatyczne
- Niestałe zmienne globalne (zainicjowane lub niezainicjowane)
- Zewnętrzne zmienne globalne const
- Wbudowane zmienne globalne const
- Przestrzenie nazw
Identyfikatory z zewnętrznym powiązaniem zazwyczaj powodują błąd linkera zduplikowanej definicji, jeśli definicje są kompilowane do więcej niż jednego pliku .cpp (ze względu na naruszenie zasady jednej definicji). Istnieje kilka wyjątków od tej reguły (dla typów, szablonów oraz funkcji i zmiennych wbudowanych) — omówimy je szerzej w przyszłych lekcjach, gdy będziemy omawiać te tematy.
Pamiętaj również, że funkcje mają domyślnie zewnętrzne połączenie. Można je uczynić wewnętrznymi za pomocą słowa kluczowego static.
Zakres zmiennej, czas trwania i podsumowanie powiązań
Ponieważ zmienne mają zakres, czas trwania i powiązanie, podsumujmy na wykresie:
| Typ | Przykład | Zakres | Czas trwania | Powiązanie | Uwagi |
|---|---|---|---|---|---|
| Lokalne zmienna | int x; | Blokuj | Automatyczny | Brak | |
| Statyczna zmienna lokalna | static int s_x; | Blokuj | Statyczny | Brak | |
| Dynamiczna zmienna lokalna | int* x { nowy int{} }; | Blokuj | Dynamiczny | Brak | |
| Parametr funkcji | void foo(int x) | Blokuj | Automatyczny | Brak | |
| Wewnętrzna niestała zmienna globalna | static int g_x; | Globalny | Statyczny | Wewnętrzny | Zainicjowany lub niezainicjowany |
| Zewnętrzna niestała globalna zmienna | int g_x; | Globalny | Statyczny | Zewnętrzny | Zainicjowany lub niezainicjowany |
| Wbudowana zmienna globalna niestała (C++17) | wbudowana int g_x; | Globalny | Statyczny | Zewnętrzny | Zainicjowany lub niezainicjowany |
| Wewnętrzna stała zmienna globalna | constexpr int g_x { 1 }; | Globalny | Statyczny | Wewnętrzny | Należy zainicjować |
| Zewnętrzna stała zmienna globalna | extern const int g_x { 1 }; | Globalny | Statyczny | Zewnętrzny | Należy zainicjować |
| Wbudowana stała zmienna globalna (C++17) | inline constexpr int g_x { 1 }; | Globalny | Statyczny | Zewnętrzny | Należy zainicjować |
Przekaż podsumowanie deklaracji
Możesz użyć deklaracji forward, aby uzyskać dostęp do funkcji lub zmiennej w innym pliku. Zakres zadeklarowanej zmiennej jest taki sam jak zwykle (zasięg globalny dla globali, zakres blokowy dla lokalnych).
| Typ | Przykład | Uwagi |
|---|---|---|
| Deklaracja forward funkcji | void foo(int x); | Tylko prototyp, bez treści funkcji |
| Deklaracja zmiennej innej niż stała | extern int g_x; | Musi być niezainicjowana |
| Deklaracja forward zmiennej const | extern const int g_x; | Musi być niezainicjowana |
| Deklaracja naprzód zmiennej constexpr | extern constexpr int g_x; | Niedozwolone, constexpr nie można zadeklarować w przód |
Zmienna constexpr (która domyślnie jest const) może zostać zadeklarowana w przód przy użyciu deklaracji forward zmiennej const. W przypadku dostępu poprzez deklarację forward zmienna będzie uważana za const (a nie constexpr).
Co to do cholery jest specyfikator klasy pamięci?
Kiedy są używane jako część deklaracji identyfikatora, static i extern słowa kluczowe nazywane są specyfikatorami klas pamięci. W tym kontekście ustawiają czas przechowywania i powiązanie identyfikatora.
C++ obsługuje 4 aktywne specyfikatory klasy pamięci:
| Specifier | Znaczenie | Uwaga |
|---|---|---|
| zewnętrzny | statyczny (lub wątek_lokalny) czas przechowywania i zewnętrzne połączenie | |
| statyczny | statyczny (lub wątek_lokalny) czas przechowywania i wewnętrzne powiązanie | |
| wątek_lokalny | przechowywanie wątków czas trwania | |
| zmienny | obiekt można modyfikować, nawet jeśli zawierający klasę jest const | |
| automatyczny | automatyczny czas przechowywania | Przestarzałe w C++11 |
| rejestr | automatyczne zapisywanie czasu trwania i wskazówka dla kompilatora, aby umieścić go w rejestrze | Przestarzałe w C++17 |
Termin specyfikatora klasy pamięci jest zwykle używany tylko w dokumentacji formalnej.

