In C / C ++, dovrei usare 'const' nei parametri e nelle variabili locali quando possibile?


13

Questa domanda è ispirata da una domanda su finalin Java .

In C / C ++, dovrei usare constquando possibile?

So che esiste già una domanda correlata sull'uso dei constparametri . Sfortunatamente quella domanda e le sue risposte non rispondono pienamente alla mia domanda, perché riguarda solo i parametri di funzione, ma vorrei anche conoscere altri casi (ad esempio: variabili locali).

Inoltre, quasi tutte le risposte a questa domanda dicono che dovremmo usare constperché contiene informazioni utili sull'accessibilità delle variabili. Ma questo sembra essere in conflitto con una risposta sull'uso di final in Java che afferma che finalpotrebbe essere superfluo se non contiene informazioni aggiuntive e quindi dovrebbe essere omesso per mantenere il codice breve e pulito.

Quindi, dovrei usare constquando possibile? In tal caso, perché i consigli per constin C ++ sono diversi dai consigli per finalin Java?

Risposte:


18

Prima di tutto, da quando hai fatto riferimento a Java final, questa è una bestia totalmente diversa rispetto a const. Final indica che il riferimento non può cambiare, ma non dice nulla sulla mutabilità. Const va oltre dicendo "un riferimento const non può mutare" che è una garanzia molto più forte. Per fare ciò in Java, lo stato interno deve essere definitivo e determinato al momento della costruzione. Const è molto più facile da usare e un oggetto esistente può essere "promosso" in un riferimento const.

Sì, dovresti usare const ogni volta che è possibile. Stipula un contratto in base al quale il codice non cambierà qualcosa. Ricorda, una variabile non const può essere passata a una funzione che accetta un parametro const. Puoi sempre aggiungere const, ma non portarlo via (non senza un cast const che è una pessima idea).

La correttezza della costanza può essere noiosa a volte, ma aiuta a garantire l'immutabilità. Questo è cruciale nel codice multi-thread in cui i thread condividono oggetti. Rende alcuni compiti più efficienti: invece di copiare lo stato, basta riutilizzare lo stesso oggetto immutabile. Le librerie potrebbero accettare i parametri const al fine di garantire al programmatore che no, il tuo oggetto non cambierà in modo imprevedibile nel buco nero che è il fegato della libreria.


1
Votazione perché lo spieghi finale constnon hai le stesse garanzie.
Bill Door,

2
La costanza riguarda la scrivibilità, non la mutabilità.
Basilevs,

@Basilevs cosa succede se si scrive su un oggetto? Muta. Come mutate un oggetto? Scrivici.

4
Cosa succede se scrivi a un riferimento const? Un errore di compilazione. Cosa succede se si scrive sull'oggetto a cui si fa riferimento da qualche parte per riferimento const tramite un altro riferimento non const? Muta. L'oggetto immutabile non può mutare, quindi il riferimento costante non fa necessariamente riferimento all'oggetto immutabile.
Basilevs,

@Basilevs la tua osservazione vale solo con riferimenti costanti. Se un oggetto stesso viene dichiarato const (non solo il riferimento), allora è più o meno immutabile (a meno che qualcuno non ne elimini in modo nefasto).
Matthew James Briggs,

4

Personalmente, constmi serve pochissimo tempo per scrivere, e pochissimo tempo per leggere, di solito molto meno di quanto ci vuole per verificare se qualche codice muta la variabile, e in realtà mi impedisce di scrivere bug (qualcuno ha mai incrementato il loro iteratore finale per caso? Eccetera)

Trovo anche che essere rigoroso sull'uso const mi guidi verso un codice migliore in altri modi, come la creazione di funzioni di supporto per eseguire un'inizializzazione non banale.


4

Non sarò d'accordo con gli altri poster e consiglierei di non usare il massimo livello constsu variabili e parametri locali. (Riferimenti e puntatori a const, cioè const T&, sono diversi e dovresti usarli per correttezza in ogni momento quando è appropriato.)

I vantaggi di alto livello constsono:

  • Illustra che le variabili locali non sono pensate per essere mutate.
  • Fornisce un errore del compilatore se si tenta di mutarli accidentalmente.

Gli svantaggi sono:

  • Disordine visivo.
  • Non può essere utilizzato su variabili "pseudo-const", ovvero variabili inizializzate in qualche modo più complicate della costruzione diretta, ma non modificate dopo, ad esempio utilizzando getline:

    std::string line; // cannot be const
    std::getline(std::cin, line);
    // line should be const from here on out
  • Impedisce l'ottimizzazione di spostamento alla chiamata di funzione e ritorno:

    std::string f1();
    std::string f2(std::string s);
    std::string f3() {
      const std::string s = f1(); // s is not meant to be modified
      // but I still want the move optimization here:
      const std::string result = f2(std::move(s)); // this doesn't move
      // and I want the compiler to move out here:
      return result; // this will probably RVO, but if not, the move
                     // constructor will not be used due to the const
    }

Ho lavorato su una base di codice in cui local è conststato usato molto e non l'ho trovato affatto utile, eppure ha riempito il codice di sottili pessimizzazioni come sopra. Personalmente preferisco adottare una politica generale di modifica delle variabili il più raramente possibile e rendere le funzioni abbastanza piccole da rendere evidente l'uso di una variabile e, anche se viene modificata, la complessità della funzione è abbastanza bassa da renderla non -problema.


2
Il tuo punto sul passaggio da è mostrare dove non stai usando il locale in modo costante, poiché (intendi) modificarlo con il movimento
Caleth,

1
@Caleth No, questo è il punto. Non intendo modificarlo. Voglio solo passare il valore o restituirlo e voglio che sia efficiente. Concettualmente, la modifica è solo un'ottimizzazione, che non intende essere osservabile (poiché le variabili non vengono utilizzate in seguito). In pratica sì, c'è una modifica, dal momento che C ++ non ha vere mosse distruttive (come ha fatto Rust). Questo è esattamente il motivo per cui non voglio la constgente del posto: perché impedisce modifiche tecniche, non solo modifiche concettuali.
Sebastian Redl,

2
Non si desidera modificare il valore , ma si desidera modificare la variabile . Puoi invece usare const & invece e non modificare nessuno dei due
Caleth,

2

La constparola chiave deve essere utilizzata per le variabili locali, proprio come i parametri. È utile perché:

  • Più facile da leggere il codice. Quando qualcuno legge la dichiarazione delle variabili, sa che non cambierà. Un'altra cosa di cui preoccuparsi durante la lettura del codice.
  • Impedisci di modificare accidentalmente la variabile
  • Nessuna penalità di runtime, tutto è controllato staticamente. È come un pranzo gratuito, constdovrebbe richiedere solo un secondo per scrivere, quindi non è un grosso problema.
  • È sempre una buona idea rendere variabili / parametri nelle applicazioni multi-thread. Anche la tua applicazione non è multi-thread, è comunque una buona abitudine.
  • Offri al compilatore C ++ l'opportunità di ottimizzare il tuo codice.

Nota che qui non c'è una risposta giusta / sbagliata. Nel tuo link, il risponditore che ha avuto il maggior numero di voti sostenuti finalnon dovrebbe essere usato localmente. Tuttavia, il prossimo risponditore lo ha fortemente raccomandato.

Se la tua funzione è semplice e banale , non dovresti aggiungere constperché tutti capiscono la tua intenzione. Tuttavia, se la logica della tua funzione non è banale, dovresti usare la parola chiave. Ricorda, c'è poco da perdere.

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.