La correttezza const può migliorare le prestazioni?


92

Ho letto numerose volte che l'applicazione della correttezza const nel codice C o C ++ non è solo una buona pratica per quanto riguarda la manutenibilità, ma può anche consentire al compilatore di eseguire ottimizzazioni. Tuttavia, ho letto anche l'esatto contrario: che non influisce affatto sulle prestazioni.

Pertanto, hai esempi in cui la correttezza const può aiutare il tuo compilatore a migliorare le prestazioni del tuo programma?


50
La correttezza della costanza è una delle MIGLIORI pratiche per quanto riguarda la manutenibilità. Se il tuo codice C ++ non è corretto, è fondamentalmente un mucchio di merda, in attesa del disastro. Non intende influire sulle prestazioni.

2
@Neil Butterworth: purtroppo non è vero il contrario.
Beta

6
Ecco un esempio in cui ha constfatto la differenza nelle prestazioni: stackoverflow.com/questions/1121791/… . Tuttavia, era essenzialmente un problema di qualità dell'implementazione. constnon ha determinato se il compilatore potesse legalmente fare l'ottimizzazione, è semplicemente successo che la versione del compilatore non è riuscita a farlo quando mancava.
Steve Jessop

3
Sono abbastanza sicuro che "morgennebel" abbia perso un "solo" nella prima frase: ha molto più senso con "non è solo una buona pratica".
IanH

2
@ IanH Sì, l'ho considerato. Ma il PO ha avuto tutto il tempo per chiarire. Vengo davvero colpito dalle persone che postano domande e poi semplicemente scompaiono.

Risposte:


77

constla correttezza non può migliorare le prestazioni perché const_caste mutablesono nella lingua e consentono al codice di infrangere le regole in modo conforme. Questo peggiora ulteriormente in C ++ 11, dove i tuoi constdati possono essere ad esempio un puntatore a std::atomic, il che significa che il compilatore deve rispettare le modifiche apportate da altri thread.

Detto questo, è banale per il compilatore guardare il codice che genera e determinare se effettivamente scrive su una data variabile e applicare le ottimizzazioni di conseguenza.

Detto questo, la constcorrettezza è una buona cosa rispetto alla manutenibilità. Altrimenti, i client della tua classe potrebbero rompere i membri interni di quella classe. Ad esempio, considera lo standard std::string::c_str(): se non potesse restituire un valore const, saresti in grado di rovinare il buffer interno della stringa!

Non utilizzare constper motivi di prestazioni. Usalo per ragioni di manutenibilità.


31
"saresti in grado di girare con il buffer interno della stringa!" - Fondamentalmente, potresti accidentalmente avvitare con il buffer interno. Gli errori del compilatore dovuti a constcartelli che dicono "stai facendo qualcosa di stupido".
Steve Jessop

4
... e i const-cast sono segnali che dicono: "l'autore di questo codice sta cercando di fare qualcosa di intelligente" ;-)
Steve Jessop

5
@Steve Jessop - o const-cast sono segnali che dicono "Sto cercando di assemblare un gruppo di codice corretto per const in uno non corretto e non posso aggiustare nessuno dei due". Il che, lascia che te lo dica, non è in alcun modo intelligente, solo fastidioso.
Michael Kohne

7
@ Michael - sì, giusto punto. Forse il cartello originale non è "stai facendo qualcosa di stupido", piuttosto "qualcuno sta facendo qualcosa di stupido".
Steve Jessop

Godbolt e Arduino mi hanno detto che la correttezza const non è solo per divertimento.
dgrat

31

Sì, può.

La maggior parte dei messaggi constè puramente a beneficio del programmatore e non aiuta il compilatore a ottimizzare perché è legale eliminarli e quindi non dicono al compilatore nulla di utile per l'ottimizzazione. Tuttavia, alcuni messaggi di posta constelettronica non possono essere eliminati (legalmente) e questi forniscono al compilatore informazioni utili per l'ottimizzazione.

Ad esempio, l'accesso a una variabile globale definita con un consttipo può essere inline mentre uno senza un consttipo non può essere inline perché potrebbe cambiare in fase di esecuzione.

https://godbolt.org/g/UEX4NB

C ++:

int foo1 = 1;
const int foo2 = 2;

int get_foo1() {
    return foo1;
}

int get_foo2() {
    return foo2;
}

asm:

foo1:
        .long   1
foo2:
        .long   2
get_foo1():
        push    rbp
        mov     rbp, rsp
        mov     eax, DWORD PTR foo1[rip] ; foo1 must be accessed by address
        pop     rbp
        ret
get_foo2():
        push    rbp
        mov     rbp, rsp
        mov     eax, 2 ; foo2 has been replaced with an immediate 2
        pop     rbp
        ret

In termini pratici, tieni presente che sebbene constpossa migliorare le prestazioni, nella maggior parte dei casi non lo farà o lo farà, ma il cambiamento non sarà evidente. L'utilità principale di constnon è l'ottimizzazione.


Steve Jessop fornisce un altro esempio nel suo commento alla domanda originale che fa emergere qualcosa che vale la pena menzionare. In un ambito di blocco, è possibile per un compilatore dedurre se una variabile verrà mutata e ottimizzata di conseguenza, indipendentemente dal constfatto che il compilatore può vedere tutti gli usi della variabile. Al contrario, nell'esempio sopra, è impossibile prevedere se foo1verrà mutato poiché potrebbe essere modificato in altre unità di traduzione. Suppongo che un ipotetico ultra-compilatore senziente potrebbe analizzare un intero programma e determinare se è valido per l'accesso in linea a foo1... ma i veri compilatori non possono.


@ericcurtin Ecco perché non ho menzionato il compilatore nella risposta. Normalmente, durante la pubblicazione dell'assembly generato, mi assicurerei di indicare il compilatore e la versione, ma questa è un'ottimizzazione che eseguirà tutti i principali compilatori di ottimizzazione, quindi non volevo dare l'impressione che fosse particolare per un compilatore.
Praxeolitic

1
@Acorn Ecco lo stesso esempio ma con un oggetto di classe: godbolt.org/z/R-Zfgc . Inoltre, le variabili nell'esempio hanno un collegamento esterno.
Praxeolitic

6

nella mia esperienza, no

Per le variabili scalari, il compilatore è in grado di determinare ogni volta che il valore viene modificato ed eseguire esso stesso l'ottimizzazione necessaria.

Per i puntatori ad array, la correttezza const non garantisce che i valori siano realmente costanti in presenza di potenziali problemi di aliasing. Quindi il compilatore non può utilizzare il modificatore const da solo per eseguire le ottimizzazioni

se stai cercando l'ottimizzazione, dovresti considerare __restrict__o speciali modificatori / attributi di funzioni: http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html


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.