2011-07-08 17 views
13

C'è un modo in C++ per dichiarare che una funzione non ha effetti collaterali? Considerare:C++: funzione di ottimizzazione senza effetti collaterali

LOG("message").SetCategory(GetCategory()); 

Supponiamo ora che la macro LOG nella build di rilascio crea un oggetto che ha NullLogEntry setCategory() definito come una funzione vuota. Quindi, in pratica, l'intera espressione potrebbe (e dovrebbe) essere ottimizzata - a parte il fatto che, in teoria, la chiamata a GetCategory() potrebbe avere alcuni effetti collaterali, quindi suppongo che al compilatore non sia consentito semplicemente buttarlo via.

Un altro esempio potrebbe essere una specializzazione del modello di funzione che ignora alcuni (o tutti) i suoi argomenti, tuttavia il compilatore non può salvare la valutazione di tali argomenti nel sito di chiamata a causa dei possibili effetti collaterali.

Ho ragione? Oppure i compilatori possono comunque ottimizzare tali chiamate? In caso contrario, c'è un modo per suggerire al compilatore che questa funzione non ha effetti collaterali, quindi se il valore di ritorno viene ignorato, l'intera chiamata può essere saltata?

+0

Fintanto che la funzione è abbastanza piccola da essere allineata, le probabilità sono molto buone che tutto il codice è ottimizzato.Ovviamente questo è un dettaglio di implementazione che dovrai verificare tu stesso. –

+0

Fondamentalmente un compilatore non è autorizzato a effettuare alcuna modifica * semantica * durante l'ottimizzazione. Rimozione di una chiamata di funzione è un cambiamento semantico. Dal momento che non puoi dire esplicitamente al compilatore "questa funzione non ha effetti collaterali", non verrà ottimizzata. –

+0

@Cicada: alcuni compilatori C++ definiscono attributi (come 'pure') che consentono di dire al compilatore che la funzione non ha effetti collaterali in modo che, in teoria, possa memorizzare i suoi risultati/ottimizzare le chiamate. –

risposta

16

Non c'è modo standard di fare così, ma alcuni compilatori hanno annotazioni che è possibile utilizzare in tal senso, ad esempio, nel GCC è possibile utilizzare il tag __attribute_pure__ in una funzione (in alternativa __attribute__((pure))) per dire al compilatore che il la funzione è pura (cioè non ha effetti collaterali). Che viene utilizzato nella libreria standard C estensivamente, in modo che per esempio:

char * str = get_some_string(); 
for (int i = 0; i < strlen(str); ++i) { 
    str[i] = toupper(str[i]); 
} 

può essere ottimizzato dal compilatore in:

char * str = get_some_string(); 
int __length = strlen(str); 
for (int i = 0; i < __length; ++ i) { 
    str[i] = toupper(str[i]); 
} 

La funzione è dichiarata nell'intestazione string.h come:

extern size_t strlen (__const char *__s) 
    __THROW __attribute_pure__ __nonnull ((1)); 

Dove __THROW è un'eccezione nessun tiro nel caso in cui si tratta di un compilatore C++ parsing la funzione, e __nonnull((1)) dice al compilatore che il primo argomento s non dovrebbe essere nullo (ad es. attiva un avvertimento se l'argomento è nullo e -La bandiera blu è usata).

+1

Sembra promettente. Qualcuno sa qualcosa di simile in MSVC? (Ovviamente una soluzione standard sarebbe meglio, ma bene ...) – imre

+0

@David: sai se il compilatore fa qualche controllo quando si colpisce la definizione della funzione di purezza? –

+0

@imre: Se MSVC è installato, prova a dare un'occhiata a 'strlen', potrebbe avere un attributo simile definito, è un buon esempio di una funzione che è nota nello standard essere * pure * in modo che essere un buon candidato per gli implementatori per usare quell'attributo. –

4

Il compilatore non può ottimizzare una chiamata alla funzione opaca. Tuttavia, se GetCategory è in linea e, quindi visibile sul sito di chiamata, il compilatore è autorizzato a e nella maggior parte dei casi lo ottimizzerà se vedrà che non ha effetti collaterali, ma non è obbligato a fare così.

Per ottenere ciò che si desidera con certezza al 100% è necessario racchiudere l'intera istruzione in una macro che verrà valutata in una dichiarazione vuota per la configurazione della versione.

+0

In che modo è possibile supportare un'istruzione in una macro? Quando il codice raggiunge correttamente il compilatore, quella macro non esiste. È stato ampliato. ** Modifica ** Non importa. La macro si espande nel nulla in modalità di produzione. –

+0

@David, avrei dovuto essere più esplicito. Modificato. –

+1

Sì, sono consapevole dell'opzione di avvolgere il tutto in una macro, ma non mi piace come soluzione per due motivi: a) è un po 'brutto, e b) in qualche modo sento che anche se in questo momento potrei solo con questi due esempi, si tratta di un problema più generale e la possibilità di contrassegnare le funzioni come prive di effetti collaterali potrebbe avere ulteriori utilizzi. L'ottimizzazione solo delle funzioni inline non è veramente sufficiente; un argomento di funzione può essere il risultato di un calcolo molto complesso (senza effetti collaterali), e se è ignorato, sarebbe comunque bello saltare l'intera chiamata. – imre

3

Questo è un problema noto con il codice della modalità di debug.

L'unica soluzione affidabile (per le chiamate di funzione) consiste nel racchiudere tutto il codice di debug all'interno della macro stessa.

Ad esempio, si potrebbe forse utilizzare il seguente codice invece:

LOG("message", GetCategory()); 

Poi il preprocessore sarebbe spazzare via l'intera dichiarazione in uscita, e che non avrebbe dovuto preoccuparsi di questo più.

Problemi correlati