2009-11-12 15 views
24

So che ci sono alcune domande sulla correttezza const dove si afferma che la dichiarazione di una funzione e la sua definizione non devono necessariamente concordare i parametri di valore. Questo perché la costanza di un parametro di valore interessa solo all'interno della funzione. Questo va bene:Corrispondenza di Const per i parametri di valore

// header 
int func(int i); 

// cpp 
int func(const int i) { 
    return i; 
} 

Sta facendo questo davvero una buona pratica? Perché non ho mai visto nessuno farlo. Ho visto questa citazione (non sono sicuro della fonte) in altri luoghi questo è stato discusso:

"In fact, to the compiler, the function signature is the same whether you include this const in front of a value parameter or not."

"Avoid const pass-by-value parameters in function declarations. Still make the parameter const in the same function's definition if it won't be modified."

Il secondo comma dice di non mettere il const nella dichiarazione. Presumo questo perché la costanza di un parametro di valore è priva di significato come parte di una definizione di interfaccia. È un dettaglio di implementazione.

In base a questa raccomandazione, è anche consigliato per i valori del puntatore dei parametri del puntatore? (Non ha senso su un parametro di riferimento dal momento che non è possibile riassegnare un riferimento.)

// header 
int func1(int* i); 
int func2(int* i); 

// cpp 
int func1(int* i) { 
    int x = 0; 

    *i = 3; // compiles without error 
    i = &x; // compiles without error 

    return *i; 
} 
int func2(int* const i) { 
    int x = 0; 

    *i = 3; // compiles without error 
    i = &x; // compile error 

    return *i; 
} 

Sommario: Fare parametri di valore è utile per la cattura di alcuni errori di logica. È una buona pratica? Vai all'estremo di lasciare il const fuori dal file di intestazione? È utile tanto per i valori del puntatore const? Perché o perché no?

Alcune referenze:

C++ const keyword - use liberally? Use of 'const' for function parameters

Un esempio di quando i parametri di valore const sono utili:

bool are_ints_equal(const int i, const int j) { 
    if (i = j) { // without the consts this would compile without error 
     return true; 
    } else { 
     return false; 
    } 
    // return i = j; // I know it can be shortened 
} 
+0

Raggiunge il "se (i = j)" errore in questo caso, ma non cattura tutti questi errori, quindi non mi entusiasmerei troppo per quella particolare logica (dato che puoi fare lo stesso errore con le variabili). Anche senza il const, il compilatore dovrebbe avvisarti di questo se dici di volere degli avvertimenti. – nobar

+0

Il punto di eccitarsi con 'if (i = j)' è rendersi conto che i parametri di valore const non sono solo fluff. L'esempio di Michael Burr è addirittura migliore di questo. – jmucchiello

+2

In una situazione in cui non state modificando i parametri delle funzioni, dovreste constarli perché A) è più sicuro, B) è auto-documentante, e C) è più debug-friendly. Inoltre, il prototipo e l'intestazione devono essere contrassegnati come const. È confuso se solo il fatto nell'intestazione della funzione. L'argomento sulla creazione di una variabile temporanea all'interno della funzione è una situazione in cui probabilmente non è necessario dichiarare il parametro (s) const. Sono i miei 2 centesimi. –

risposta

7

mio prendere su di esso:

Non è una cattiva idea, ma il problema è minore e la vostra energia potrebbe essere meglio spesi per altre cose.

Nella tua domanda ha fornito un buon esempio di quando potrebbe prendere un errore, ma a volte anche finire per fare qualcosa di simile:

void foo(const int count ...) 
{ 
    int temp = count; // can't modify count, so we need a copy of it 
    ++temp; 

    /* ... */ 
} 

I pro ei contro sono minori in entrambi i casi.

+3

+1 per aver detto che non è una cattiva idea, e per aver notato il problema è minore. Ma prima di copiare il parametro all'interno, vorrei semplicemente rimuovere il const (tranne forse se dovessi copiare "count" sempre, come principio di non operare su un parametro, e non solo a causa del const che ti impedisce) –

+8

di solito quando modifichi la variabile in questo modo stai cambiando il significato semantico. Ad esempio: void foo (const int index0based) {const int index1based = index0based + 1;} Potresti semplicemente chiamarlo index e cambiarlo, ma questo è molto più chiaro per il programmatore di scarsa manutenzione che arriva in 5 anni. – Bill

+0

@ Bill, punto eccellente! –

9

ho letto molte volte che fanno i parametri di valore in una funzione const è una brutta cosa da fare perché non è necessario.

Tuttavia, a me di tanto in tanto mi sembra utile controllare che la mia implementazione non faccia qualcosa che non intendo (come nell'esempio alla fine della domanda).

Quindi, mentre non può aggiungere valore al chiamante, a volte mi aggiunge un po 'di valore come implementatore e non richiede nulla al chiamante. Quindi non vedo alcun danno usarlo.

Ad esempio, potrei implementare una funzione C che richiede un paio di puntatori a un buffer, un puntatore all'inizio e un puntatore alla fine. Inserirò i dati nel buffer, ma voglio assicurarmi di non sovraccaricare la fine. Quindi all'interno della funzione c'è il codice che incrementerà un puntatore mentre aggiungo dati ad esso. Portando il puntatore alla fine del buffer un parametro const assicurerà che non codifichi un bug che incrementa accidentalmente il puntatore del limite di fine invece del puntatore che dovrei davvero incrementare.

Quindi una funzione FillArray con una firma come questo:

size_t fillArray(data_t* pStart, data_t* const pEnd); 

mi impedirà di incrementare accidentalmente pEnd quando ho davvero dire di incrementare pStart. Non è una cosa enorme, ma sono abbastanza sicuro che tutti quelli che hanno programmato per un periodo di tempo in C hanno incontrato un simile bug.

+0

Eccellente. Stavo cercando un buon esempio di valore di puntatore const. – jmucchiello

1

Sfortunatamente, alcuni compilatori (sto osservando te, Sun CC!) Differenziano erroneamente gli argomenti dichiarati const e quelli non dichiarati, e puoi ottenere errori sulle funzioni non definite.

-2

mi piace const correttezza per situazioni come questa:
void foo(const Bar &b) //I know b cannot be changed
{
//do something with b
}

Questo mi permette di usare b senza timore di modificarlo, ma non devono pagare il costo di un costruttore di copia.

+8

Non stiamo parlando di parametri di riferimento. Solo parametri di valore. – jmucchiello

0

Penso che questo dipenda dal tuo stile personale.

Non aggiunge né sottrarre ciò che i client possono passare alla funzione. In sostanza è come un'asserzione in fase di compilazione. Se ti aiuta a sapere che il valore non cambierà, vai avanti e fallo, ma non vedo un grosso motivo per farlo.

Un motivo per cui non è possibile farlo è che la costante del parametro value è un dettaglio di implementazione di cui i client non hanno bisogno di essere a conoscenza. Se successivamente (intenzionalmente) modifichi la tua funzione in modo che cambi effettivamente quel valore, dovrai cambiare la firma della tua funzione, che costringerà i tuoi clienti a ricompilare.

Questo è simile al motivo per cui alcune persone consigliano di non avere metodi virtuali pubblici (le funzioni virtualità sono un dettaglio di implementazione che dovrebbe essere nascosto ai client), ma non sono in quel campo particolare.

+2

Rileggi la domanda. Il file di intestazione non ha il const perché, come dici tu, al chiamante non importa se l'implementazione modifica una variabile locale. Questa è una domanda strettamente sul fatto che ne valga la pena dal lato dell'implementazione. – jmucchiello

0

Se è presente una parola chiave const; significa che il valore di 'i' (che è di tipo const) non può essere modificato. Se il valore di 'i' è cambiato all'interno funzione foo compilatore gettare errore: "

Can not modify const object

Ma cambiare '* i' (vale a dire * i = 3;) significa che non sta modificando il valore di 'i', ma il valore di indirizzo puntato da 'i'

in realtà, la funzione const è appropriato per oggetti di grandi dimensioni che non devono essere alterati dalla funzione.

0

tutti dobbiamo sbrogliare qualcun altro codice C++ di tanto in tanto. E questo il codice C++ di qualcun altro è un disastro completo per definizione: D

Quindi la prima cosa che faccio sempre per decodificarlo (flusso di dati globale locale &) è messa const in ogni definizione di variabile finché il compilatore non si lamenta. Ciò significa anche argomenti valore costanti e aiuta davvero ad evitare le variabili che sono state modificate nel mezzo della funzione senza che me ne accorga ...

Così ho davvero apprezzare quando quel qualcun altro ha const ovunque (inclusi i parametri di valore): D

Problemi correlati