puntatori non opzionali vs. riferimenti non costanti in C ++


12

In Altre funzionalità di C ++, Argomenti di riferimento della Guida allo stile di Google C ++ , ho letto che i riferimenti non costanti non devono essere utilizzati.

Tutti i parametri passati per riferimento devono essere etichettati const.

È chiaro che guardare le chiamate di funzione che usano i riferimenti come argomenti è assolutamente confuso per i programmatori C, ma C e C ++ ora sono linguaggi diversi. Se è richiesto un parametro di output , usando un puntatore per un parametro di output richiesto, si può saltare l'intero corpo della funzione, il che rende più complicata l'implementazione di una funzione (aumenta formalmente la complessità e la profondità ciclomatica di una funzione).

Vorrei rendere il codice C ++ il più semplice possibile da comprendere / mantenere, quindi sono generalmente interessato a leggere le guide di stile di codifica. Ma per quanto riguarda l'adattamento delle migliori pratiche in una squadra, penso che comprendere la logica alla base degli elementi della guida di stile sia un fattore importante.

I riferimenti non costanti sono davvero così negativi? Il loro divieto è solo specifico di Google o è una regola comunemente accettata? Cosa giustifica lo sforzo extra per l'implementazione dei parametri di output come puntatori?


2
"l'uso di un puntatore per questo fa saltare l'intero corpo della funzione" ehm, cosa?
maniaco del cricchetto,

@ratchetfreak Ho provato a chiarire questo. Ammetto che funzioni come questa potrebbero mostrare alcuni difetti di progettazione. Un puntatore è sempre formalmente facoltativo, quindi deve essere verificato prima di dereferenziarlo.
Lupo,

4
La guida di stile C ++ di Google è piuttosto arretrata. Secondo la mia opinione soggettiva, dovrebbe essere bruciato.
Siyuan Ren,

Per quanto riguarda questo particolare articolo, penso che la logica sia quella di costringere i programmatori a scrivere una e commerciale quando gli argomenti possono essere mutati mostrano un intento più chiaro.
Siyuan Ren,

4
La Guida allo stile di Google è stata scritta com'era per supportare il codice omogeneo nei progetti legacy di Google. Se non stai lavorando a progetti legacy (che sono stati scritti con questa guida di stile dall'inizio), probabilmente non dovresti usarlo (specifica molte regole che non vanno bene per il nuovo codice (c ++ 11, c ++ 14 , c ++ 17)).
utnapistim,

Risposte:


18

La logica alla base della guida di stile di Google è semplicemente quella di chiarire dal sito di chiamata di una funzione se un parametro è un parametro di input o un parametro di output. (Vedi qui per ulteriori discussioni.) Altre lingue rendono espliciti i parametri in base alla progettazione; C #, ad esempio, ha una outparola chiave che deve essere utilizzata nel sito della chiamata . Poiché C ++ non lo rende esplicito, Google ha scelto di utilizzare const ref. contro il puntatore per chiarire.

È solo una regola di Google? No, ma dubito che sia molto diffuso. Non credo di averlo visto al di fuori della guida di stile e dei gruppi di Google che aderiscono esplicitamente a parti della guida di stile di Google. (Ad esempio, mi è piaciuta l'idea quando ho letto per la prima volta la guida di stile di Google anni fa e l'ho usata per alcuni dei miei codici.)

In particolare, le Linee guida di base C ++ recentemente annunciate preferiscono i valori di ritorno ai parametri di output per (quasi) tutto e usano riferimenti non costanti per il resto. L'uso da parte di Google di puntatori e riferimenti potrebbe rendere più chiari i parametri di output, ma i valori di ritorno sono ancora più chiari. Ora che C ++ 11 ha mosse standardizzate (riferimenti a valori &&, per rendere economici rendimenti di molti tipi) e tuple (che consentono un modo semplice per restituire più valori), molti dei casi d'uso per i parametri di uscita non sono più applicabili.

Le Linee guida di base C ++ hanno alcuni grandi nomi (Bjarne Stroustrup, Herb Sutter) alle spalle, sono supportate da Microsoft e abbracciano le ultime funzionalità C ++ (a differenza della guida di stile di Google), quindi mi aspetto che i suoi consigli siano più popolari di quelli di Google.


Grazie per la risposta (anche per la breve escursione a C #). Una facile revisione è ovviamente un punto importante, specialmente nei progetti Open Source. Con rendimenti economici nel moderno C ++, queste considerazioni perderanno la loro importanza. Con software legacy precedenti e compilatori obsoleti potrebbe essere ancora utile.
Lupo,

Non me ne sono dimenticato, ma le Linee guida di base C ++ non sono così veloci da ottenere. È interessante notare che la sua filosofia mostra la logica alla base delle regole e anche una visione modernizzata della programmazione ("Esprimere idee direttamente nel codice" legge un po 'come lo Zen di Python) come un modo di comunicare.
Lupo,

Supplemento: collegamento diretto alla sezione Filosofia delle Linee guida del codice C ++.
Lupo,

1

Ci sono 2 opzioni per gestire un puntatore non valido passato, primo controllo e ritorno anticipato o lasciare che sia un comportamento indefinito (se ti interessa più la velocità che la robustezza).

Il controllo è semplice come:

void foo(void* buffer){
    if(buffer == nullptr)
        return;

    //actually foo

    // note no increase in indentation required

}

Questo tipo di controllo è generalmente accettato come controllo dei parametri. Se vedi il codice è abbastanza chiaro che ti aspetti che un puntatore non nullo venga passato e che ritorni presto se no. Questo ti consente di non preoccuparti troppo di puntatori non validi.


Bene, ho pensato a questo modello e lo trovo assolutamente ragionevole. Purtroppo non sembra chiaro come assert(buffer);sapendo che l'asserzione è attiva solo per la versione di debug, a volte vorrei avere un rt_assert(buffer);che genera un'eccezione. Il rientro returndell'aspetto è un po 'pericoloso ... A proposito: lo snippet di codice è una buona illustrazione della mia domanda sui puntatori per l'output.
Lupo,

1

Dipende dalla tua osservazione If an output parameter is required.

L'unico posto in cui è richiesta una firma di funzione per avere un parametro di output è quando è specificato da un'API esterna, e in tal caso è sufficiente racchiudere l'API esterna in qualcosa che assicuri che sia sempre presente un punto valido.

Internamente si evitano i parametri di output estendendo il tipo restituito per essere un composto di tutti gli "out"


Vuoi dire, l'unico posto dove non sono in grado di fornire un puntatore non obbligatorio? Vero, ma non sono sicuro che la tua regola The only place where...sia davvero applicabile a tutti i casi. Ecco come si presenta: evita i parametri di output nelle funzioni dei tuoi programmi. Vero per i nuovi programmi.
Lupo,

1
Sì, evita i parametri di output, preferisci i tipi di ritorno compositi, modificati per renderlo più chiaro
Caleth
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.