Vendimi sulla costante correttezza


133

Quindi, perché è sempre consigliabile utilizzare const il più spesso possibile? Mi sembra che usare const possa essere più una seccatura che un aiuto in C ++. Ma poi di nuovo, sto arrivando a questo dal punto di vista di Python: se non vuoi che qualcosa cambi, non cambiarlo. Detto questo, ecco alcune domande:

  1. Sembra che ogni volta che segnare qualcosa come const, ricevo un errore e devo cambiare qualche altra funzione da qualche parte per essere const. Quindi questo mi fa cambiare un'altra funzione da qualche altra parte. È qualcosa che diventa più semplice con l'esperienza?

  2. I vantaggi dell'utilizzo di const sono davvero sufficienti a compensare il problema? Se non hai intenzione di cambiare un oggetto, perché non semplicemente non scrivere codice che non lo modifica?

Dovrei notare che a questo punto, mi concentro maggiormente sui vantaggi dell'utilizzo di const per scopi di correttezza e manutenibilità, anche se è anche bello avere un'idea delle implicazioni sulle prestazioni.


1
Retrospettiva di 8 anni, ma ... Che ne dici di velocizzare il tuo codice 100x (visto dal vivo)?
Lorro,

1
Controlla qui la mia risposta (domanda correlata, direi la stessa risposta): stackoverflow.com/questions/42310477/… A proposito: I love loveconst
Gines Hidalgo

Risposte:


158

Questo è l'articolo definitivo su "const correttezza": https://isocpp.org/wiki/faq/const-correctness .

In breve, usare const è una buona pratica perché ...

  1. Ti protegge dalla modifica accidentale di variabili che non sono destinate a essere modificate,
  2. Ti protegge dall'assegnazione di variabili accidentali e
  3. Il compilatore può ottimizzarlo. Ad esempio, sei protetto da

    if( x = y ) // whoops, meant if( x == y )

Allo stesso tempo, il compilatore può generare codice più efficiente perché sa esattamente quale sarà lo stato della variabile / funzione in ogni momento. Se stai scrivendo codice C ++ stretto, questo è buono.

Hai ragione nel dire che può essere difficile usare coerenza costante, ma il codice finale è più conciso e sicuro da programmare. Quando si fa molto sviluppo C ++, i vantaggi di questo si manifestano rapidamente.


Ho sempre supposto che i valori const potessero essere liberamente memorizzati nella cache e quindi evitare molti problemi di concorrenza o migliorare la velocità. È vero?
Phil H,

3
Sicuro. constle variabili possono migliorare la velocità, nel senso che il compilatore può generare un codice più ottimale perché conosce l'intento e l'uso completi della variabile. Noterai la differenza? Bene, questo è discutibile sulla tua domanda. Per quanto riguarda la concorrenza, le variabili const sono di sola lettura, il che significa che non sono necessari blocchi esclusivi su tali variabili poiché il valore sarà sempre lo stesso.
Jordan Parmer,

4
A partire da C ++ 11 la libreria standard presuppone anche constsicurezza dei thread e il trattamento del proprio codice in questo modo semplifica il controllo di eventuali problemi di multi-thread ed è un modo semplice per fornire garanzie API per gli utenti API.
pm

3
Per me, uno dei maggiori valori aggiunti della correttezza const è che si sa solo guardando i prototipi di funzioni quando i puntatori fanno riferimento a dati che non sono mai mutati dalla funzione (cioè solo input).
cp.engr

1
Non dimenticare che esiste una costanza logica e fisica . Qualsiasi oggetto aggregato contenuto contrassegnato come mutabile può cambiare, anche se contrassegnarlo come tale implica che non ha nulla a che fare con la costanza logica dell'oggetto contenente.
Adrian

128

Ecco un pezzo di codice con un errore comune da cui la correttezza costante può proteggerti da:

void foo(const int DEFCON)
{
   if (DEFCON = 1)     //< FLAGGED AS COMPILER ERROR! WORLD SAVED!
   {
       fire_missiles();
   }
}

19
Quindi stiamo dicendo che const è necessaria perché qualche idiota sanguinante ha scelto "=" come operatore di assegnazione in C? ;-)
Steve Jessop,

37
Naturalmente, la maggior parte dei compilatori moderni mette in guardia sugli incarichi in condizionali e tutti attiviamo gli avvisi di trattamento come bandiera degli errori, a destra: ->
Jack Bolding,

7
Non essere troppo duro su questo esempio: questo è lo stesso esempio evangelizzato da alcuni sviluppatori per convincerci a usare if (0 == i) invece di if (i == 0). Alla fine, il modello di codice di Doug può essere usato al di fuori dell'istruzione "if". La cosa importante è che mostra uno dei vantaggi di const in modo umoristico. + 1.
paercebal,

2
Alcuni compilatori (e lint) lo avvertono da molto tempo, e questo è molto più utile per catturare questo errore di battitura di const: codepad.org/Nnf5JUXV .

7
@Roger supponi che viviamo in un mondo in cui le build sono pulite e prive di avvisi. La mia esperienza è che in molti codici gli avvisi si perdono nel rumore. Inoltre, c'è un sacco di codice che fa assegnazioni nell'espressione if e molti sosterranno che è uno stile valido, "buono".
Doug T.

62

Sembra che ogni volta che segnare qualcosa come const, ricevo un errore e devo cambiare qualche altra funzione da qualche parte per essere const. Quindi questo mi fa cambiare un'altra funzione da qualche altra parte. È qualcosa che diventa più semplice con l'esperienza?

Per esperienza, questo è un mito totale. Succede quando non const-correct si trova con codice const-correct, certo. Se si progetta const-correct dall'inizio, questo non dovrebbe MAI costituire un problema. Se fai qualcosa di const, e poi qualcos'altro non si compila, il compilatore ti sta dicendo qualcosa di estremamente importante e dovresti prenderti il ​​tempo per risolverlo correttamente .


7
Questo mi ha aiutato a prevenire così tanti bug in cui avevo una funzione const per chiamare una funzione non const perché avevo dimenticato che modifica i dati sottostanti.
Mooing Duck,

9
Pochissime persone iniziano sempre con basi di codice pulite. La maggior parte della codifica è la manutenzione del codice legacy, in cui il commento citato è abbastanza accurato. Uso const quando scrivo nuove funzioni foglia, ma mi chiedo se valga la pena inseguire cose attraverso una mezza dozzina o una dozzina di livelli di chiamata di codice sconosciuto.
Warren Dew,

3
Questo è completamente sbagliato nella mia esperienza. I tipi di punti nidificati creano il più grande mal di testa per questo tipo di cose, in cui è possibile avere più quantificatori di costanti in un singolo tipo.
Noldorin,

4
"Se progetti const-correct dall'inizio", quante volte hai il lusso di forzare la const-correttezza dall'inizio ?? La maggior parte di noi ha a che fare con numerose API e librerie su base giornaliera dove questo non è il caso e c'è poco che puoi fare al riguardo. Quindi sono d'accordo con il sentimento dei PO "Sembra che ogni volta che segnare qualcosa come const ottengo un errore un" ...
nyholku,

@WarrenDew Questo è un argomento transitivo; se gli autori originali avessero usato constcorrettamente (cioè "dall'inizio"), in effetti non ci sarebbe stato un problema, che è esattamente il punto!
Razze di leggerezza in orbita

31

Non fa per te quando scrivi il codice inizialmente. È per qualcun altro (o tu qualche mese dopo) che sta guardando la dichiarazione del metodo all'interno della classe o dell'interfaccia per vedere cosa fa. Non modificare un oggetto è un'informazione significativa da cui trarre profitto.


1
Questo è solo un po 'vero. Const viene utilizzato anche come protezione per imporre le variabili interne tramite interfacce e così via.
Jordan Parmer,

Lo è, ma puoi applicarlo attraverso pratiche di codifica disciplinate e gli stati dei poster. Il vero vantaggio deriva da ciò che si riflette nell'API.
Antonio Haley,

2
Esattamente. È meglio avere "const int Value = 5;" di "int ConstValue = 5;". +1.
paercebal,

6
Il momento giusto per inserire la correttezza const è quando si scrive inizialmente l'API. Altrimenti avrai problemi con l'avvelenamento da cost quando lo aggiorni (motivo per cui aggiungerlo al vecchio codice è una questione completamente diversa rispetto a farlo nel nuovo codice).
Donal Fellows,

@DonalFellows questo non sta dicendo messo in const più tardi. Sta dicendo che otterrai i benefici in seguito, quando leggi il codice con const già presente
Caleth,

27

Se usi const rigorosamente, rimarrai sorpreso da quante poche variabili reali ci siano nella maggior parte delle funzioni. Spesso non più di un contatore di loop. Se il tuo codice sta raggiungendo quel punto, senti una calda sensazione dentro ... convalida per compilazione ... il regno della programmazione funzionale è vicino ... puoi quasi toccarlo ora ...


1
dal C ++ 17 e la bontà di constexpr sto scrivendo test di unità di tempo di compilazione ... avvicinandomi ancora ...
QBziZ,

22

const è una promessa che stai facendo come sviluppatore e che sta cercando l'aiuto del compilatore per far rispettare.

Le mie ragioni per essere const-correct:

  • Comunica ai clienti della tua funzione che non modificherai la variabile o l'oggetto
  • Accettare argomenti per riferimento costante ti dà l'efficienza del passaggio per riferimento con la sicurezza del passaggio per valore.
  • Scrivere le interfacce come const corrette consentirà ai client di usarle. Se si scrive la propria interfaccia per accettare riferimenti non costanti, i client che utilizzano const dovranno eliminare la costanza per poter lavorare con l'utente. Ciò è particolarmente fastidioso se la tua interfaccia accetta caratteri non costanti * e i tuoi clienti usano std :: stringhe, poiché puoi ottenere solo un carattere const * da loro.
  • Usando const arruolerai il compilatore per mantenerti onesto in modo da non cambiare erroneamente qualcosa che non dovrebbe cambiare.

20

La mia filosofia è che se hai intenzione di usare un linguaggio schizzinoso con controlli del tempo di compilazione che sfruttarlo al meglio, puoi farlo. constè un modo forzato di compilazione per comunicare ciò che intendi ... è meglio di quanto non lo siano mai i commenti o doxygen. Stai pagando il prezzo, perché non derivarne il valore?


20

Programmare C ++ senza const è come guidare senza la cintura di sicurezza.

Indossare la cintura di sicurezza ogni volta che sali in macchina è una seccatura e 364 giorni su 365 arriverai in sicurezza.

L'unica differenza è che quando hai problemi con la tua auto la sentirai immediatamente, mentre con la programmazione senza const potresti dover cercare per due settimane ciò che ha causato quell'incidente solo per scoprire che hai inavvertitamente incasinato un argomento di funzione che hai passato per riferimento non const per efficienza.


18

Per la programmazione integrata, l'utilizzo con constprudenza durante la dichiarazione di strutture di dati globali può far risparmiare molta RAM, facendo sì che i dati costanti si trovino nella ROM o nel flash senza copiarli nella RAM all'avvio.

Nella programmazione quotidiana, l'uso constattento ti aiuta a evitare di scrivere programmi che si arrestano in modo anomalo o si comportano in modo imprevedibile perché tentano di modificare valori letterali di stringa e altri dati globali costanti.

Quando si lavora con altri programmatori su progetti di grandi dimensioni, l'utilizzo constcorretto aiuta a prevenire la limitazione degli altri programmatori.


13

constti aiuta a isolare il codice che "cambia le cose" alle tue spalle. Quindi, in una classe, contrassegneresti tutti i metodi che non cambiano lo stato dell'oggetto come const. Ciò significa che le constistanze di quella classe non saranno più in grado di chiamare nessun non- constmetodo. In questo modo, ti viene impedito di chiamare accidentalmente funzionalità che possono modificare il tuo oggetto.

Inoltre, constfa parte del meccanismo di sovraccarico, quindi puoi avere due metodi con firme identiche, ma uno con conste uno senza. L'uno con constviene chiamato per i constriferimenti e l'altro per i non constriferimenti.

Esempio:

#include <iostream>

class HelloWorld {
    bool hw_called;

public:
    HelloWorld() : hw_called(false) {}

    void hw() const {
        std::cout << "Hello, world! (const)\n";
        // hw_called = true;  <-- not allowed
    }

    void hw() {
        std::cout << "Hello, world! (non-const)\n";
        hw_called = true;
    }
};

int
main()
{
    HelloWorld hw;
    HelloWorld* phw1(&hw);
    HelloWorld const* phw2(&hw);

    hw.hw();    // calls non-const version
    phw1->hw(); // calls non-const version
    phw2->hw(); // calls const version
    return 0;
}

13

la correttezza const è una di quelle cose che hanno davvero bisogno di essere in atto fin dall'inizio. Come hai scoperto, è un grande dolore aggiungerlo in seguito, soprattutto quando c'è molta dipendenza tra le nuove funzioni che stai aggiungendo e le vecchie funzioni non corrette che già esistono.

In un sacco di codice che scrivo, ne è valsa davvero la pena perché tendiamo a usare molto la composizione:

class A { ... }
class B { A m_a; const A& getA() const { return m_a; } };

Se non avessimo la correttezza const, allora dovresti ricorrere al ritorno di oggetti complessi in base al valore per assicurarti che nessuno stesse manipolando lo stato interno della classe B alle tue spalle.

In breve, la correttezza const è un meccanismo di programmazione difensiva per salvarti dal dolore lungo la strada.


7

Supponi di avere una variabile in Python. Sai che non dovresti modificarlo. E se lo fai accidentalmente?

Il C ++ ti offre un modo per proteggerti dal fare accidentalmente qualcosa che prima non avresti dovuto fare. Tecnicamente puoi aggirarlo comunque, ma devi fare un lavoro extra per spararti.


4

C'è un bell'articolo qui su const in c ++. È un'opinione piuttosto semplice ma spero che possa aiutare alcuni.


3

Quando usi la parola chiave "const", stai specificando un'altra interfaccia per le tue classi. C'è un'interfaccia che include tutti i metodi e un'interfaccia che include solo i metodi const. Ovviamente questo ti consente di limitare l'accesso ad alcune cose che non desideri vengano modificate.

Sì, diventa più facile con il tempo.


2

Mi piace la correttezza const ... in teoria. Ogni volta che ho provato ad applicarlo rigorosamente in pratica, alla fine si è rotto e const_cast inizia a insinuarsi nel rendere brutto il codice.

Forse sono solo i motivi di design che uso, ma const finisce sempre per essere un pennello troppo ampio.

Ad esempio, immagina un semplice motore di database ... ha oggetti schema, tabelle, campi ecc. Un utente può avere un puntatore "const Table" che significa che non gli è permesso di modificare lo schema della tabella stessa ... ma per quanto riguarda la manipolazione i dati associati alla tabella? Se il metodo Insert () è contrassegnato da const, allora internamente deve gettare via la costanza per manipolare effettivamente il database. Se non è contrassegnato const, non protegge dal richiamo del metodo AddField.

Forse la risposta è quella di dividere la classe in base ai requisiti di costanza, ma ciò tende a complicare il design più di quanto vorrei per il vantaggio che ne deriva.


Penso che il tuo esempio sia un caso di uso eccessivo di const, ma non dimenticare il modificatore mutabile, che può essere applicato alle variabili di istanza per rimuovere la costanza.
Zooba,

2
Quando una funzione Insert () sarebbe mai stata contrassegnata const se non fosse erroneamente denominata? L'aggiunta di cose di solito modifica la cosa a cui l'hai aggiunta, il che significa che non è const. Quello che volevi davvero era un TableWithConstSchema.
Greg Rogers,

Potrei aggiungere un'altra classe, ma non voglio rendere l'API inutilmente complessa per motivi di correttezza const.
Rob Walker,

1

Puoi dare suggerimenti al compilatore anche con const .... come da codice seguente

#include <string>

void f(const std::string& s)
{

}
void x( std::string& x)
{
}
void main()
{
    f("blah");
    x("blah");   // won't compile...
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.