c++ Qual è la differenza tra const int*, const int*const e int const*?




pointers (12)

Ho sempre incasinato come usare const int* , const int * const e int const * correttamente. Esiste un insieme di regole che definiscono ciò che puoi o non puoi fare?

Voglio conoscere tutte le cose da fare e quelle da non fare in termini di incarichi, passaggio alle funzioni, ecc.


Answer #1

Come quasi tutti hanno sottolineato:

Qual è la differenza tra const X* p , X* const p e const X* const p ?

Devi leggere le dichiarazioni dei puntatori da destra a sinistra.

  • const X* p significa "p punta ad una X che è const": l'oggetto X non può essere modificato tramite p.

  • X* const p significa "p è un puntatore const su una X che non è const": non puoi cambiare il puntatore p stesso, ma puoi cambiare l'oggetto X tramite p.

  • const X* const p significa "p è un puntatore const su una X che è const": non puoi cambiare il puntatore p stesso, né puoi cambiare l'oggetto X tramite p.


Answer #2

Il const con l'int su entrambi i lati renderà il puntatore a int costante .

const int *ptr=&i;

o

int const *ptr=&i;

const dopo '*' renderà il puntatore costante a int .

int *const ptr=&i;

In questo caso, tutti questi sono puntatori a numero intero costante , ma nessuno di questi è un puntatore costante.

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

In questo caso tutti sono puntatori a numero intero costante e ptr2 è puntatore costante a numero intero costante . Ma ptr1 non è un puntatore costante.

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

Answer #3

Questa domanda mostra esattamente perché mi piace fare le cose nel modo in cui ho menzionato nella mia domanda : const è dopo che il tipo id è accettabile?

In breve, trovo che il modo più semplice per ricordare la regola è che "const" segue la cosa a cui si applica. Quindi, nella tua domanda, "int const *" significa che l'int è costante, mentre "int * const" significherebbe che il puntatore è costante.

Se qualcuno decide di metterlo in prima fila (es: "const int *"), come eccezione speciale in quel caso si applica alla cosa dopo di essa.

A molte persone piace usare quell'eccezione speciale perché pensano che sia più carina. Non mi piace, perché è un'eccezione e quindi confonde le cose.


Answer #4

Ciò riguarda principalmente la seconda riga: best practice, assegnazioni, parametri di funzione, ecc.

Pratica generale. Cerca di rendere tutto ciò che puoi. O per dirla in un altro modo, fai in modo che tutto const com const , e poi rimuovi esattamente il set minimo di const necessario per permettere al programma di funzionare. Questo sarà di grande aiuto per raggiungere la correttezza delle costanti, e contribuirà a garantire che i bug sottili non vengano introdotti quando le persone cercano e assegnano cose che non dovrebbero modificare.

Evita const_cast <> come la peste. Ci sono uno o due casi d'uso legittimi, ma sono molto pochi e distanti tra loro. Se stai provando a cambiare un oggetto const , farai molto meglio a trovare chi ha dichiarato di essere const al primo passo e discuterne con loro per raggiungere un consenso su cosa dovrebbe accadere.

Che conduce molto bene in compiti. Puoi assegnare qualcosa solo se non è const. Se vuoi assegnare qualcosa che è const, vedi sopra. Ricorda che nelle dichiarazioni int const *foo; e int * const bar; cose diverse sono const - altre risposte qui hanno trattato mirabilmente questo argomento, quindi non ci entrerò.

Parametri di funzione:

Passa per valore: ad esempio void func(int param) non ti interessa in un modo o nell'altro nel sito di chiamata. L'argomento può essere fatto che ci sono casi d'uso per dichiarare la funzione come void func(int const param) ma che non ha alcun effetto sul chiamante, solo sulla funzione stessa, in quanto qualsiasi valore viene passato non può essere modificato dalla funzione durante la chiamata.

Passa per riferimento: es. void func(int &param) Ora fa la differenza. Come appena dichiarato func è permesso di cambiare param , e qualsiasi sito di chiamata dovrebbe essere pronto ad affrontare le conseguenze. Cambiare la dichiarazione in void func(int const &param) cambia il contratto e garantisce che func possa ora cambiare param , cioè che cosa viene passato è ciò che tornerà fuori. Come altri hanno notato, questo è molto utile per passare a basso costo un oggetto di grandi dimensioni che non si desidera modificare. Passare un riferimento è molto più economico che passare un oggetto di grandi dimensioni in base al valore.

Passa col puntatore: ad esempio void func(int *param) e void func(int const *param) Questi due sono praticamente sinonimi delle rispettive controparti di riferimento, con l'avvertenza che la funzione chiamata ora ha bisogno di verificare nullptr meno di qualche altra garanzia contrattuale assicura func che non riceverà mai un nullptr in param .

Parere di opinione su questo argomento. Dimostrare la correttezza in un caso come questo è terribilmente difficile, è semplicemente troppo facile commettere un errore. Quindi non correre rischi e controlla sempre i parametri del puntatore per nullptr . Ti risparmierai dolore e sofferenza e sarai difficile trovare insetti a lungo termine. E per quanto riguarda il costo del controllo, è poco costoso, e nei casi in cui l'analisi statica incorporata nel compilatore può gestirlo, l'ottimizzatore lo eliderà comunque. Attiva Link Time Code Generation per MSVC, o WOPR (credo) per GCC, e otterrai il programma in modo esteso, vale a dire anche nelle chiamate alle funzioni che attraversano un limite del modulo del codice sorgente.

Alla fine della giornata tutto quanto sopra rende un caso molto solido per preferire sempre i riferimenti ai puntatori. Sono solo più al sicuro.


Answer #5

Ho avuto lo stesso dubbio di te fino a quando non ho trovato questo book dal Guru del C ++ Scott Meyers. Fai riferimento al terzo elemento in questo libro in cui parla in dettaglio sull'utilizzo di const .

Segui questo consiglio

  1. Se la parola const appare a sinistra dell'asterisco, ciò che viene indicato è costante
  2. Se la parola const appare a destra dell'asterisco, il puntatore stesso è costante
  3. Se const appare su entrambi i lati, entrambi sono costanti

Answer #6

Per coloro che non conoscono la regola orario / a spirale: iniziare dal nome della variabile, spostarla in senso orario (in questo caso, andare indietro) al puntatore o al tipo successivo . Ripeti fino al termine dell'espressione.

ecco una demo:


Answer #7

Penso che tutto sia già stato risolto qui, ma voglio solo aggiungere che dovresti stare attento a typedef s! NON sono solo sostituzioni di testo.

Per esempio:

typedef char *ASTRING;
const ASTRING astring;

Il tipo di astring è char * const , non const char * . Questo è uno dei motivi per cui tendo sempre a mettere a destra del tipo, e mai all'inizio.


Answer #8
  1. Riferimento costante:

    Un riferimento a una variabile (qui int), che è costante. Passiamo principalmente alla variabile come riferimento, perché i riferimenti sono di dimensioni più ridotte rispetto al valore effettivo, ma c'è un effetto collaterale e questo è perché è come un alias della variabile attuale. Potremmo cambiare accidentalmente la variabile principale attraverso il nostro pieno accesso all'alias, quindi la rendiamo costante per prevenire questo effetto collaterale.

    int var0 = 0;
    const int &ptr1 = var0;
    ptr1 = 8; // Error
    var0 = 6; // OK
    
  2. Puntatori costanti

    Una volta che un puntatore costante punta a una variabile, non può puntare a nessuna altra variabile.

    int var1 = 1;
    int var2 = 0;
    
    int *const ptr2 = &var1;
    ptr2 = &var2; // Error
    
  3. Puntatore a costante

    Un puntatore attraverso il quale non è possibile modificare il valore di una variabile che punta è noto come puntatore a costante.

    int const * ptr3 = &var2;
    *ptr3 = 4; // Error
    
  4. Puntatore costante a una costante

    Un puntatore costante a una costante è un puntatore che non può né modificare l'indirizzo a cui punta e né può modificare il valore mantenuto a quell'indirizzo.

    int var3 = 0;
    int var4 = 0;
    const int * const ptr4 = &var3;
    *ptr4 = 1;     // Error
     ptr4 = &var4; // Error
    

Answer #9

Ci sono molti altri punti sottili che circondano la correttezza const in C ++. Suppongo che la domanda qui sia stata semplicemente su C, ma darò alcuni esempi correlati dal momento che il tag è C ++:

  • Spesso si passano grandi argomenti come stringhe come TYPE const & che impedisce che l'oggetto venga modificato o copiato. Esempio :

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

    Ma TYPE & const senso perché i riferimenti sono sempre const.

  • Dovresti sempre etichettare i metodi di classe che non modificano la classe come const , altrimenti non puoi chiamare il metodo da un TYPE const & riferimento TYPE const & . Esempio :

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

  • Esistono situazioni comuni in cui sia il valore restituito che il metodo dovrebbero essere const. Esempio :

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

    In effetti, i metodi const non devono restituire i dati della classe interna come riferimento-non-const.

  • Di conseguenza, si deve spesso creare sia un metodo const sia un metodo non const usando l'overloading const. Ad esempio, se si definisce T const& operator[] (unsigned i) const; , quindi probabilmente vorrai anche la versione non-const data da:

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

Afaik, non ci sono funzioni const in C, le funzioni non membro non possono essere esse stesse const in C ++, i metodi const potrebbero avere effetti collaterali e il compilatore non può usare le funzioni const per evitare chiamate di funzioni duplicate. In effetti, anche un semplice int const & riferimento potrebbero testimoniare il valore a cui si riferisce essere cambiato altrove.


Answer #10

La regola generale è che la parola chiave const applica a ciò che la precede immediatamente. Eccezione, un const iniziale si applica a quanto segue.

  • const int* è uguale a int const* e significa "puntatore a costante int" .
  • const int* const è uguale a int const* const e significa "puntatore costante a costante int" .

Modifica: per il Dos e non fare, se questa risposta non è sufficiente, potresti essere più preciso su ciò che vuoi?


Answer #11

La sintassi della dichiarazione C e C ++ è stata ripetutamente descritta come un esperimento fallito, dai designer originali.

Invece, chiamiamo il tipo "puntatore a Type "; Lo chiamerò Ptr_ :

template< class Type >
using Ptr_ = Type*;

Ora Ptr_<char> è un puntatore al char .

Ptr_<const char> è un puntatore a const char .

E const Ptr_<const char> è un puntatore const char per const char .

Là.


Answer #12

Semplice utilizzo di 'const'

L'uso più semplice è dichiarare una costante nominata. Per fare ciò, si dichiara una costante come se fosse una variabile ma si aggiunga 'const' prima di essa. Si deve inizializzarlo immediatamente nel costruttore perché, ovviamente, non è possibile impostare il valore in un momento successivo in quanto lo cambierebbe. Per esempio,

const int Constant1=96; 

creerà una costante intera, chiamata in modo inimmaginabile 'Costante1', con il valore 96.

Tali costanti sono utili per i parametri che vengono utilizzati nel programma ma non devono essere modificati dopo la compilazione del programma. Ha un vantaggio per i programmatori rispetto al comando '#define' del preprocessore C in quanto è compreso e utilizzato dal compilatore stesso, non solo sostituito nel testo del programma dal preprocessore prima di raggiungere il compilatore principale, quindi i messaggi di errore sono molto più utili .

Funziona anche con i puntatori, ma bisogna stare attenti dove 'const' per determinare se il puntatore o ciò a cui punta è costante o entrambi. Per esempio,

const int * Constant2 

dichiara che Constant2 è un puntatore variabile su un numero intero costante e

int const * Constant2

è una sintassi alternativa che fa lo stesso, mentre

int * const Constant3

dichiara che Constant3 è puntatore costante a un numero intero e variabile

int const * const Constant4

dichiara che Constant4 è un puntatore costante a un numero intero costante. Fondamentalmente 'const' si applica a tutto ciò che è alla sua sinistra immediata (a parte se non c'è nulla nel qual caso si applica a qualunque sia il suo diritto immediato).

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





const