Jaka jest różnica między const int*, const int * const i int const*?

I always burdel up how to use const int*, const int * const, i int const * poprawnie. Czy istnieje zestaw zasad określających, co możesz, a czego nie możesz zrobić?

Chcę wiedzieć, co robić i czego nie robić, jeśli chodzi o zadania, przechodzenie do funkcji itp.

Author: MD XF, 2009-07-17

14 answers

Czytaj do tyłu (zgodnie z zgodnie z ruchem wskazówek zegara/spiralnym):

  • int* - Wskaźnik do int
  • int const * - Wskaźnik do const int
  • int * const - const wskaźnik do int
  • int const * const - const wskaźnik do const int

Teraz pierwszy {[5] } może być po obu stronach typu tak:

  • const int * == int const *
  • const int * const == int const * const

Jeśli chcesz naprawdę zwariować, możesz robić takie rzeczy jak to:

  • int ** - pointer to pointer to int
  • int ** const - Wskaźnik const do wskaźnika do int
  • int * const * - wskaźnik do wskaźnika const do int
  • int const ** - A pointer to a pointer to a const int
  • int * const * const - wskaźnik const do wskaźnika const do int
  • ...

I aby upewnić się, że jesteśmy jasne co do znaczenia const

const int* foo;
int *const bar; //note, you actually need to set the pointer 
                //here because you can't change it later ;)

foo jest zmiennym wskaźnikiem do stałej liczby całkowitej. To pozwala zmienić to, co wskazujesz, ale nie wartość, na którą wskazujesz. Najczęściej jest to widoczne dla ciągów w stylu C, gdzie masz wskaźnik do const char. Możesz zmienić, który ciąg znaków wskazujesz, ale nie możesz zmienić zawartości tych ciągów. Jest to ważne, gdy sam ciąg znaków znajduje się w segmencie danych programu i nie powinien być zmieniany.

bar jest stałym lub stałym wskaźnikiem do wartości, którą można zmienić. To jest jak odniesienie bez dodatkowego cukru składniowego. Z tego powodu, zazwyczaj używasz referencji, w której używasz wskaźnika T* const, chyba że musisz zezwolić na wskaźniki NULL.

 1806
Author: Matt Price,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-17 05:10:35

Dla tych, którzy nie wiedzą o prawoskrętnych / spiralnych regułach: Zacznij od nazwy zmiennej, przesuń taktowanie zegara (w tym przypadku przesuń do tyłu) do następnego wskaźnika lub typu. Powtarzaj aż wyrażenie się skończy.

Oto demo:

wskaźnik do int

wskaźnik const do int const

wskaźnik do int const

wskaźnik do const int

const wskaźnik do int

 246
Author: Shijing Lv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-10 04:44:53

Myślę, że wszystko jest już tutaj, ale chcę tylko dodać, że należy uważać na typedefs! To nie są tylko zamienniki tekstu.

Na przykład:

typedef char *ASTRING;
const ASTRING astring;

Typem astring jest char * const, a nie const char *. Jest to jeden z powodów, dla których zawsze kładę const po prawej stronie typu, a nigdy na początku.

 126
Author: Kaz Dragon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-17 05:15:35

Jak prawie wszyscy wskazywali:

Jaka jest różnica między const X* p, X* const p i const X* const p?

Musisz przeczytać deklaracje wskaźników od prawej do lewej.

  • const X* p oznacza" p wskazuje na X, który jest const": obiekt X nie może być zmieniony przez P.

  • X* const p oznacza "p jest wskaźnikiem const na X, który nie jest const": nie możesz zmienić wskaźnika p, ale możesz zmienić obiekt X za pomocą p.

  • const X* const p oznacza "p jest wskaźnikiem const na X, który jest const": nie możesz zmienić wskaźnika p, ani nie możesz zmienić obiektu x przez P.

 45
Author: luke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-26 14:20:07
  1. Stałe odniesienie:

    Odniesienie do zmiennej (tutaj int), która jest stała. Przekazujemy zmienną jako odniesienie głównie dlatego, że referencje są mniejsze niż rzeczywista wartość, ale istnieje efekt uboczny, a to dlatego, że jest to jak alias do rzeczywistej zmiennej. Możemy przypadkowo zmienić główną zmienną poprzez nasz pełny dostęp do aliasu, więc robimy to stałe, aby zapobiec temu efektowi ubocznemu.

    int var0 = 0;
    const int &ptr1 = var0;
    ptr1 = 8; // Error
    var0 = 6; // OK
    
  2. Stała wskaźniki

    Gdy stały wskaźnik wskazuje na zmienną, nie może wskazać żadnej innej zmiennej.

    int var1 = 1;
    int var2 = 0;
    
    int *const ptr2 = &var1;
    ptr2 = &var2; // Error
    
  3. Wskaźnik do stałej

    Wskaźnik, za pomocą którego nie można zmienić wartości zmiennej, którą wskazuje, jest znany jako wskaźnik na stałą.

    int const * ptr3 = &var2;
    *ptr3 = 4; // Error
    
  4. Stały wskaźnik do stałej

    Stały wskaźnik na stałą jest wskaźnikiem, który nie może zmienić adresu, na który wskazuje i nie może zmień wartość przechowywaną pod tym adresem.

    int var3 = 0;
    int var4 = 0;
    const int * const ptr4 = &var3;
    *ptr4 = 1;     // Error
     ptr4 = &var4; // Error
    
 40
Author: Behrooz Tabesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-13 19:32:44

To pytanie pokazuje dokładnie Dlaczego lubię robić rzeczy tak, jak wspomniałem w moim pytaniu czy const po type id jest akceptowalny?

W skrócie, uważam, że najprostszym sposobem na zapamiętanie zasady jest to, że "const" idzie po rzecz, do której się odnosi. Więc w twoim pytaniu, "int const *" oznacza, że int jest stała, podczas gdy "int * const" oznacza, że wskaźnik jest stała.

Jeśli ktoś zdecyduje się umieścić go na samym przodzie (np.: "const int*"), jako specjalny wyjątek w tym przypadku odnosi się do rzeczy po nim.

Wiele osób lubi używać tego wyjątku, ponieważ uważają, że wygląda ładniej. Nie podoba mi się to, ponieważ jest to wyjątek, a tym samym myli rzeczy.

 16
Author: T.E.D.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:47

Ogólna zasada jest taka, że słowo kluczowe const odnosi się do tego, co bezpośrednio je poprzedza. Wyjątek, początek const odnosi się do tego, co następuje.

  • const int* jest tym samym co int const* i oznacza "Wskaźnik do stałej int" .
  • const int* const jest tym samym co int const* const i oznacza "stały wskaźnik do stałej int" .

Edit: Dla Dos i nie, jeśli ta odpowiedź nie wystarczy, czy mógłbyś być bardziej precyzyjny o tym, czego chcesz?

 14
Author: AProgrammer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-17 05:13:33

Proste użycie 'const'

Najprostszym zastosowaniem jest zadeklarowanie nazwanej stałej. Aby to zrobić, deklaruje się stałą tak, jakby była zmienną, ale dodaje się przed nią 'const'. Trzeba ją zainicjować natychmiast w konstruktorze, ponieważ, oczywiście, nie można później ustawić wartości, ponieważ to by ją zmieniało. Na przykład,

const int Constant1=96; 

Stworzy stałą całkowitą, niewyobrażalnie zwaną 'Stałą1', o wartości 96.

Takie stałe są przydatne dla parametrów, które są używane w programie, ale nie muszą być zmieniane po skompilowaniu programu. Ma on przewagę programistów nad poleceniem preprocesora C '# define ' w tym, że jest rozumiany i używany przez sam kompilator, a nie tylko podstawiany do tekstu programu przez preprocesor przed dotarciem do głównego kompilatora, więc komunikaty o błędach są znacznie bardziej pomocne.

Działa również ze wskaźnikami, ale trzeba uważać, gdzie 'const', aby określić, czy wskaźnik lub co wskazuje na jest stałe albo jedno i drugie. Na przykład,

const int * Constant2 

Deklaruje, że Stała2 jest zmiennym wskaźnikiem do stałej liczby całkowitej i

int const * Constant2

Jest składnią alternatywną, która robi to samo, podczas gdy

int * const Constant3

Deklaruje, że Stała3 jest stałym wskaźnikiem do zmiennej całkowitej i

int const * const Constant4

Deklaruje, że Stała4 jest stałym wskaźnikiem do stałej liczby całkowitej. Zasadniczo "const" odnosi się do tego, co znajduje się po jego bezpośrednim lewej stronie (INNE niż Jeśli nie ma tam nic, w którym to przypadku odnosi się do tego, co jest jego bezpośrednio w prawo).

Ref: http://duramecho.com/ComputerInformation/WhyHowCppConst.html

 12
Author: ufukgun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-17 13:31:45

Miałem takie same wątpliwości jak ty, dopóki nie natknąłem się na tę książkę autorstwa Guru C++ Scotta Meyersa. Zapoznaj się z trzecią pozycją w tej książce, gdzie mówi szczegółowo o użyciu const.

Po prostu postępuj zgodnie z tą radą

  1. Jeśli słowo const pojawia się po lewej stronie gwiazdki, to na co wskazuje stała
  2. Jeśli słowo const pojawia się po prawej stronie gwiazdki, sam wskaźnik jest stały
  3. Jeśli const pojawia się po obu stronach, obie są stałe
 7
Author: rgk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-21 13:56:12

Istnieje wiele innych subtelnych punktów otaczających poprawność const w C++. Domyślam się, że pytanie dotyczy po prostu C, ale podam kilka powiązanych przykładów, ponieważ TAG jest C++:

  • Często przekazujesz Duże argumenty, takie jak łańcuchy znaków, jako TYPE const &, co zapobiega modyfikowaniu lub kopiowaniu obiektu. Przykład:

    TYPE& TYPE::operator=(const TYPE &rhs) { ... return *this; }

    Ale TYPE & const jest bez znaczenia, ponieważ odniesienia są zawsze const.

  • Należy zawsze oznaczyć klasę metody, które nie modyfikują klasy jako const, w przeciwnym razie nie można wywołać metody z referencji TYPE const &. Przykład:

    bool TYPE::operator==(const TYPE &rhs) const { ... }

  • Są typowe sytuacje, w których zarówno wartość zwracana, jak i metoda powinny być const. Przykład:

    const TYPE TYPE::operator+(const TYPE &rhs) const { ... }

    W rzeczywistości metody const nie mogą zwracać wewnętrznych danych klasy jako odniesienia do non-const.

  • W rezultacie, często trzeba stworzyć zarówno metodę const jak i non-const używając const przeciążenie. Na przykład, jeśli zdefiniujesz T const& operator[] (unsigned i) const;, to prawdopodobnie będziesz chciał również wersję non-const podaną przez:

    inline T& operator[] (unsigned i) { return const_cast<char&>( static_cast<const TYPE&>(*this)[](i) ); }

Afaik, nie ma funkcji const w C, Funkcje nieczłonkowe same w sobie nie mogą być const w c++, metody const mogą mieć skutki uboczne, a kompilator nie może używać funkcji const do unikania duplikatów wywołań funkcji. W rzeczywistości nawet proste odniesienie int const & może świadczyć o tym, że wartość, do której się odnosi, może zostać zmieniona gdzie indziej.

 5
Author: Jeff Burdges,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-13 10:50:54

To proste, ale trudne. Należy pamiętać, że możemy zamienić kwalifikator const na dowolny typ danych(int, char, float, itd.).

Zobaczmy poniższe przykłady.


const int *p ==> *p jest tylko do odczytu [p jest wskaźnikiem do stałej liczby całkowitej]

int const *p ==> *p jest tylko do odczytu [p jest wskaźnikiem do stałej liczby całkowitej]


int *p const ==> Błędna Wypowiedź. Kompilator wyrzuca błąd składni.

int *const p ==> p jest tylko do odczytu [p jest stały wskaźnik do liczby całkowitej]. Ponieważ wskaźnik p jest tylko do odczytu, deklaracja i definicja powinny znajdować się w tym samym miejscu.


const int *p const ==> Błędna Wypowiedź. Kompilator wyrzuca błąd składni.

const int const *p ==> *p jest tylko do odczytu

const int *const p1 ==> *p i p są tylko do odczytu [p jest stałym wskaźnikiem do stałej liczby całkowitej]. Ponieważ wskaźnik p jest tylko do odczytu, deklaracja i definicja powinny znajdować się w tym samym miejscu.


int const *p const ==> Błędne Stwierdzenie. Kompilator wyrzuca błąd składni.

int const int *p ==> Błędna Wypowiedź. Kompilator wyrzuca błąd składni.

int const const *p ==> *p jest tylko do odczytu i jest równoważne int const *p

int const *const p ==> *p i p są tylko do odczytu [p jest stałym wskaźnikiem do stałej liczby całkowitej]. Ponieważ wskaźnik p jest tylko do odczytu, deklaracja i definicja powinny znajdować się w tym samym miejscu.

 5
Author: Abhijit Sahu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-17 21:12:24

Składnia deklaracji C i C++ była wielokrotnie opisywana przez oryginalnych projektantów jako nieudany eksperyment.

Zamiast nazwijmy typ "wskaźnik do Type"; nazwę go Ptr_:

template< class Type >
using Ptr_ = Type*;

Teraz Ptr_<char> jest wskaźnikiem do char.

Ptr_<const char> jest wskaźnikiem do const char.

I const Ptr_<const char> jest wskaźnikiem const do const char.

Tam.

Tutaj wpisz opis obrazka

 5
Author: Cheers and hth. - Alf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-06 00:18:21

Const z int po obu stronach uczyni wskaźnikiem do stałej int .

const int *ptr=&i;

Lub

int const *ptr=&i;

Const PO ' * ' zrobi stały wskaźnik do int .

int *const ptr=&i;

W tym przypadku wszystkie z nich są wskaźnikiem do stałej liczby całkowitej , ale żaden z nich nie jest stałym wskaźnikiem.

 const int *ptr1=&i, *ptr2=&j;

W tym przypadku wszystkie są wskaźnikiem do stałej liczby całkowitej , a ptr2 jest stałym wskaźnikiem do stałej liczby całkowitej . Ale ptr1 nie jest stała pointer.

int const *ptr1=&i, *const ptr2=&j;
 2
Author: Hunter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-23 08:44:06

Dotyczy to głównie drugiej linii: najlepszych praktyk, zadań, parametrów funkcji itp.

Ogólna praktyka. Postaraj się zrobić wszystko const, co możesz. Albo Inaczej mówiąc, zacznij od wszystkiego const, a następnie usuń dokładnie minimalny zestaw const niezbędnych do działania programu. Będzie to bardzo pomocne w osiągnięciu poprawności i pomoże upewnić się, że subtelne błędy nie zostaną wprowadzone, gdy ludzie spróbują przypisać do rzeczy, które są nie powinno się modyfikować.

Unikaj const_cast jak plaga. Istnieje jeden lub dwa uzasadnione przypadki użycia, ale są one bardzo nieliczne. Jeśli próbujesz zmienić obiekt const, lepiej znajdź tego, kto go zadeklarował const w pierwszym tempie i porozmawiaj z nim o sprawie, aby osiągnąć konsensus co do tego, co powinno się wydarzyć.

Co prowadzi bardzo starannie do zadań. Możesz przypisać do czegoś tylko wtedy, gdy nie jest const. Jeśli chcesz przypisać w coś, co jest const, patrz wyżej. Pamiętaj, że w deklaracjach int const *foo; i int * const bar; różne rzeczy są const - Inne odpowiedzi tutaj poruszały ten problem w sposób godny podziwu, więc nie będę się w to wdawać.

Parametry funkcji:

Pass by value: np. void func(int param) you don ' t care one way or the other at the calling site. Można argumentować, że istnieją przypadki użycia do deklarowania funkcji jako void func(int const param), ale to nie ma wpływu na wywołujący, tylko na samą funkcję, w tym, co wartość przekazywana nie może być zmieniona przez funkcję podczas wywołania.

Podaj przez odniesienie: np. void func(int &param) Teraz to robi różnicę. Jak właśnie zadeklarowano {[11] } może się zmienić param, a każda strona wywołująca powinna być gotowa do radzenia sobie z konsekwencjami. Zmiana deklaracji na void func(int const &param) zmienia umowę i gwarantuje, że {[11] } nie może teraz zmienić param, co oznacza, że to, co zostało przekazane, to to, co wróci. Jak inni zauważyli, jest to bardzo przydatne do taniego przechodzenia dużej obiekt, którego nie chcesz zmieniać. Przekazywanie referencji jest o wiele tańsze niż przekazywanie dużego obiektu przez wartość.

Podaj pointer: np. void func(int *param) i void func(int const *param) te dwa są niemal równoznaczne ze swoimi odpowiednikami referencyjnymi, z zastrzeżeniem, że wywołana funkcja musi teraz sprawdzić, czy nullptr, chyba że jakaś inna umowna gwarancja zapewni func, że nigdy nie otrzyma nullptr w param.

Opiniotwórczy artykuł na ten temat. Udowodnienie poprawności w takim przypadku jest cholernie trudno, ale za łatwo popełnić błąd. Więc nie ryzykuj i zawsze sprawdzaj parametry wskaźnika nullptr. Oszczędzisz sobie bólu i cierpienia oraz trudnych do znalezienia błędów w dłuższej perspektywie. A co do kosztu czeku, to jest drogo, a w przypadkach, gdy analiza statyczna wbudowana w kompilator da radę to i tak optimizer ją ominie. Włącz Generowanie kodu czasu łącza dla MSVC, lub WOPR (chyba) dla GCC, a dostaniesz go programowo, tzn. nawet w wywołaniach funkcji, które przekraczają granicę modułu kodu źródłowego.

Na koniec dnia wszystkie powyższe argumenty są bardzo solidne, aby zawsze preferować odniesienia do wskaźników. Są bezpieczniejsze.

 1
Author: dgnuff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-15 07:59:23