Domanda

Avevo assunto che la forma canonica per l'operatore +, supponendo l'esistenza di un operatore sovraccarico + = funzione membro, fosse così:

const T operator+(const T& lhs, const T& rhs)
{
    return T(lhs) +=rhs;
}

Ma mi è stato fatto notare che anche questo avrebbe funzionato:

const T operator+ (T lhs, const T& rhs)
{
    return lhs+=rhs;
}

In sostanza, questo modulo trasferisce la creazione del temporaneo dal corpo dell'implementazione alla chiamata di funzione.

Sembra un po 'imbarazzante avere tipi diversi per i due parametri, ma c'è qualcosa che non va nella seconda forma? C'è un motivo per preferire l'uno rispetto all'altro?

È stato utile?

Soluzione

Con la domanda modificata, il primo modulo sarebbe preferito. Molto probabilmente il compilatore ottimizzerà il valore di ritorno (è possibile verificarlo posizionando un breakpoint nel costruttore per T). La prima forma prende anche entrambi i parametri come const, il che sarebbe più desiderabile.

Ricerca sull'argomento ottimizzazione del valore restituito , come questo collegamento come esempio rapido: http://www.cs.cmu.edu/~gilpin/c++/performance.html

Altri suggerimenti

Non sono sicuro che ci sia molta differenza nel codice generato per entrambi.

Tra questi due preferirei (personalmente) la prima forma poiché trasmette meglio l'intenzione. Questo è rispetto sia al tuo riutilizzo dell'operatore + = sia al linguaggio del passaggio di tipi templatizzati da const & amp ;.

Preferirei il primo modulo per la leggibilità.

Ho dovuto pensarci due volte prima di vedere che il primo parametro veniva copiato. Non me lo aspettavo. Pertanto, poiché entrambe le versioni sono probabilmente altrettanto efficienti, sceglierei una più facile da leggere.

const T operator+(const T& lhs, const T& rhs)
{
    return T(lhs)+=rhs;
}

perché non questo se vuoi la terseness?

Il mio primo pensiero è che la seconda versione potrebbe essere infinitamente più veloce della prima, perché nessun argomento viene inserito nello stack come argomento. Tuttavia, ciò dipende molto dal compilatore e dipende, ad esempio, dal fatto che il compilatore esegua o meno l'ottimizzazione del valore restituito con nome.

In ogni caso, in caso di dubbio, non scegliere mai un guadagno di prestazioni molto piccolo che potrebbe non esistere e che molto probabilmente non sarà necessario: scegli la versione più chiara, che è la prima.

In realtà, il secondo è preferito. Come indicato nello standard c ++,

  

3.7.2 / 2: durata della memorizzazione automatica

     

Se ha un oggetto automatico denominato   inizializzazione o un distruttore con   effetti collaterali, non deve essere   distrutto prima della fine del suo blocco,   né deve essere eliminato come   ottimizzazione anche se sembra essere   inutilizzato, tranne che un oggetto di classe o   la sua copia può essere eliminata come   specificato in 12.8.

Cioè, poiché un oggetto temporaneo senza nome viene creato utilizzando un costruttore di copie, il compilatore potrebbe non utilizzare l'ottimizzazione del valore restituito. Per il secondo caso, tuttavia, è consentita l'ottimizzazione del valore restituito senza nome. Nota che se il tuo compilatore implementa l'ottimizzazione del valore restituito, il codice migliore è

const T operator+(const T& lhs, const T& rhs)
{
    T temp(lhs);
    temp +=rhs;
    return temp;
}

Penso che se li abbinassi ad entrambi (lo farei dal momento che sono solo funzioni di inoltro e presumibilmente la funzione operatore + = () è fuori linea), ti avvicineresti alla generazione di codice indistinguibile. Detto questo, il primo è più canonico. La seconda versione è inutilmente "carina".

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top