2014-10-18 7 views
8

Il Google C++ Style Guide opera una netta distinzione (rigorosamente seguito da cpplint.py) tra i parametri di input (→ ref const, il valore) e input-output o parametri di output (→ puntatori non const):guida di stile di Google sui parametri di ingresso/uscita come puntatori

I parametri delle funzioni C/C++ sono immessi nella funzione, emettono dalla funzione o entrambi. I parametri di input sono in genere valori o riferimenti const, mentre i parametri di output e input/output sono puntatori non-const .

E ancora:

In realtà si tratta di una convenzione molto forte nel codice di Google che gli argomenti di input sono valori o riferimenti const mentre argomenti di uscita sono puntatori.

Ma non riesco a capire perché gli argomenti di input/output (lascio gli argomenti di output a parte) non dovrebbero essere passati per riferimento. Su StackOverflow ci sono molti argomenti relativi a questa domanda: ad es. here, la risposta accettata dicono chiaramente che

è per lo più una questione di stile

ma che se

si vuole essere in grado di passare null, è necessario utilizzare un puntatore

Quindi, qual è il punto di sempre richiedere un puntatore se devo nt per evitare che il puntatore sia nullo? Perché usare solo riferimenti per argomenti di input?

+2

Se non è un puntatore, sai che non verrà modificato. Questa è un'informazione utile. Se i parametri out possono essere riferimenti o i parametri possono essere indicatori, è necessario osservare costantemente la documentazione o ricordare tutto. – molbdnilo

+5

Solo perché proviene da Google non significa che abbia senso. –

+0

FWIW, [Conversazione di Titus's CppCon] (https://www.youtube.com/watch?v=NOCElcMcFik) – chris

risposta

23

La ragione di chiedere che i parametri di output vengono passati come puntatori è semplice:

Si rende chiaro presso il sito chiamata che l'argomento è potenzialmente sta per essere mutato:

foo(x, y);  // x and y won't be mutated 
bar(x, &y); // y may be mutated 

Quando una base di codice si evolve e subisce cambiamenti incrementali che vengono esaminati da persone che potrebbero non conoscere l'intero contesto in ogni momento, è importante essere in grado di comprendere il contesto e l'impatto di un cambiamento il più rapidamente possibile. Quindi, con questa regola di stile, è immediatamente chiaro se una modifica introduce una mutazione.

5

Il punto che stanno facendo (che non sono d'accordo con) è che dicono che ho una certa funzione

void foo(int a, Bar* b); 

Se l'argomento b è facoltativo, o non è necessario a volte, è possibile chiamare la funzione in questo modo

foo(5, nullptr); 

Se la funzione è stata dichiarata come

void foo(int a, Bar& b); 

Th it non c'è modo di non passare in un Bar.

Questo punto (il mio enfasi) è completamente basato sull'opinione e fino alla discrezione dello sviluppatore.

Infatti è molto forte convenzione nel codice Google che argomenti di input sono valori o riferimenti const mentre argomenti di uscita sono puntatori.

Se si intende che b sia un parametro di output, uno dei seguenti è perfettamente valido e ragionevole.

void foo(int a, Bar* b); // The version Google suggests 
void foo(int a, Bar& b); // Reference version, also perfectly fine. 
+2

Titus sembrava inclinarsi di più verso il callsite, mostrando che qualsiasi cosa fosse passata poteva essere modificata nel suo video CppCon. – chris

+0

Grazie per le vostre spiegazioni: capisco che sia "perfettamente valido e ragionevole" per gli argomenti di output. Ma per quanto riguarda gli argomenti di input-output? Ho pensato che fosse più pericoloso usare i puntatori invece dei riferimenti per loro! – suizokukan

+0

@suizokukan, Nulla di ciò che hai detto nella tua domanda suggerisce dei puntatori per i parametri di input. – chris

1

Essi probabilmente usano per coerenza perché utilizzano parametri di uscita sia come riferimenti alla memoria esistente (che stanno modifica variabili precedentemente create) e come uscite reali (gli argomenti di uscita sono presume essere assegnato dalla funzione stessa). Per coerenza, lo usano come un modo per indicare più chiaramente gli input e gli output.

Se non è mai necessario un metodo/funzione per assegnare la memoria del parametro di uscita, ad esempio restituendo un puntatore da una ricerca o allocando la memoria stessa e restituendolo tramite un puntatore, utilizzare i riferimenti. Se è necessario farlo ma non si preoccupa di utilizzare i puntatori per fungere da indicazione sull'input o l'output di un parametro, utilizzare i riferimenti per i parametri di output, quando appropriato. Non è assolutamente necessario utilizzare i puntatori in tutti i casi, a meno che non siano richiesti i requisiti di tale funzione/metodo.

4

Sei prima domanda: "Allora, qual è il punto di sempre richiede un puntatore se voglio evitare il puntatore ad essere null?"

L'utilizzo di un puntatore annuncia al chiamante che la loro variabile può essere modificata. Se sto chiamando foo(bar), è bar andando a essere modificato? Se chiamo foo(&bar), è possibile che il valore di bar possa essere modificato.
Ci sono molti esempi di funzioni che prendono in un null che indicano un parametro di output opzionale (la parte superiore della mia testa time è un buon esempio.)

tua seconda domanda: "Perché usare solo i riferimenti per argomenti di input"

L'utilizzo di un parametro di riferimento è più semplice rispetto all'argomento del puntatore.

int foo(const int* input){ 
    int return = *input; 

    while(*input < 100){ 
     return *= *input; 
     (*input)++; 
    } 
} 

Questo codice riscritto con un riferimento assomiglia:

int foo(const int& input){ 
    int return = input; 

    while(input < 100){ 
     return *= input; 
     input++; 
    } 
} 

Si può vedere che l'utilizzo di un const int& input semplifica il codice.

Problemi correlati