Quando ottieni il massimo var, qual è la differenza tra l’uso di funzioni e macro

leggendo il codice combase.cpp, trovo che segue:

/* We have to ensure that we DON'T use a max macro, since these will typically */ /* lead to one of the parameters being evaluated twice. Since we are worried */ /* about concurrency, we can't afford to access the m_cRef twice since we can't */ /* afford to run the risk that its value having changed between accesses. */ template inline static T ourmax( const T & a, const T & b ) { return a > b ? a : b; } 

Non capisco perché “la macro massima porta a uno dei parametri da valutare due volte”?

Considera un utilizzo simile a questo esempio di codice :

 #define max(a,b) (a>b?a:b) int main() { int a = 0; int b = 1; int c = max(a++, b++); cout << a << endl << b << endl; return 0; } 

L'intenzione probabilmente era di stampare 1 e 2 , ma la macro si espande in:

 int c = a++ > b++ ? a++ : b++; 

b viene incrementato due volte e il programma stampa 1 e 3 .

Quindi,
In alcuni casi, le espressioni passate come argomenti alle macro possono essere valutate più di una volta.

Sebbene Als abbia spiegato abbastanza chiaramente il problema immediato, vedo due problemi più grandi. Il primo è semplice: max non può essere una macro, poiché è un modello di funzione standard, definito in . (Nel caso di VC ++, è necessario definire NOMINMAX per utilizzare . Ma poiché è sempre preferibile utilizzare una funzione standard quando fa il lavoro, dovresti praticamente sempre aggiungere NOMINMAX al tuo preprocessore definendolo ed NOMINMAX con esso.)

Il secondo è ancora più preoccupante, poiché mostra una mancanza di comprensione del codice. I commenti fanno riferimento alla “concorrenza” e suggeriscono che, utilizzando la funzione, non ci sono problemi di concorrenza. Questo è semplicemente sbagliato. Se qualsiasi altro thread (o processo, nel caso della memoria condivisa) può modificare uno degli argomenti, il comportamento non è definito. In particolare, come scritto, il compilatore probabilmente leggerà uno dei due valori; gli argomenti sono riferimenti. Ma indipendentemente da come lo scrivi, il compilatore può rileggere i valori; e anche se così non fosse, non c’è nulla che assicuri che gli accessi siano atomici. Chiunque abbia scritto il commento non comprende i principi di base del codice multithread.