2011-11-19 2 views
13

confrontare le funzioni di integrazione generici:Passando oggetto functor per valore vs per riferimento (C++)

template <class F> double integrate(F integrand); 

con

template <class F> double integrate(F& integrand); 

o

template <class F> double integrate(const F& integrand); 

quali sono i pro ei contro di ogni ? STL usa il primo approccio (passa per valore), significa che è il più universale?

+0

STL di solito utilizza il primo approccio perché sorgono molti problemi quando si utilizzano contenitori di riferimenti, ecc. –

+2

Come ovunque: A seconda di cosa 'F', queste versioni possono variare dall'essere identiche a molto diverse. Se 'F' è di stato, solo la versione centrale potrebbe essere possibile. –

+0

Fondamentalmente, stai mettendo i requisiti per i tuoi utenti qualunque sia la forma che scegli. Se per valore, stai richiedendo che ti diano un funtore che può essere copiato senza perdita di integrità. Se per riferimento, devi richiedere che ti diano qualcosa con una durata adatta a qualsiasi utente tu stia mettendo. – Mordachai

risposta

19

Gli oggetti funzione di solito dovrebbero essere piccoli, quindi non credo che il loro superamento per valore risentirà di prestazioni notevoli (confrontarlo con il lavoro svolto dalla funzione nel suo corpo). Se passi per valore, puoi anche ottenere dall'analisi del codice, perché un parametro di valore è locale alla funzione e l'ottimizzatore può dire quando e quando non è possibile omettere un carico da un membro di dati del functor.

Se funtore è stateless, passando come argomento implica alcun costo - il byte riempimento che funtore prende non deve avere alcun valore particolare (nel Itanium Abi usata da GCC almeno). Quando si usano i riferimenti, è sempre necessario passare un indirizzo.

L'ultimo (const T&) ha lo svantaggio che in C++ 03 non funziona per le funzioni raw, perché in C++ 03 il programma è mal formato quando si tenta di applicare const a un tipo di funzione (ed è un caso SFINAE). Le implementazioni più recenti invece ignorano const quando applicate ai tipi di funzione.

Il secondo (T&) presenta l'ovvio inconveniente che non è possibile passare ai funtori temporanei.

Per farla breve, in genere li passerei di valore, a meno che non veda un chiaro vantaggio in casi concreti.

3

Dato il contesto, F dovrebbe essere un "oggetto callable" (qualcosa di simile a una funzione libera o di una classe con un operatore() definito)

Ora, dal momento che un nome di funzione libera non può essere un L- valore, la seconda versione non è adatta a questo. Il terzo presuppone che F :: operator() sia const (ma potrebbe non essere il caso, se è necessario modificare lo stato di F) Il primo funziona su una "propria copia", ma richiede che F sia copiabilabile.

Nessuno dei tre è "universale", ma il primo è molto probabile che funzioni nei casi più comuni.

5

STL utilizza il primo approccio (passaggio per valore)

Certo, le librerie standard passano iteratori e funtori per valore. Si presuppone (giustamente o erroneamente) di essere economici da copiare, e questo significa che se si scrive un iteratore o un functor che è costoso da copiare, potrebbe essere necessario trovare un modo per ottimizzarlo in seguito.

Ma questo è solo per gli scopi per cui le librerie standard utilizzano i funtori - per lo più sono predicati, anche se ci sono anche cose come . Se stai integrando una funzione, questo suggerisce una sorta di librerie di matematica, nel qual caso suppongo che potresti avere molte più probabilità di occuparti di funzioni che portano molto stato. Ad esempio, potresti avere una classe che rappresenta i polinomi dell'ennesimo ordine, con i coefficienti n + 1 come membri di dati non statici.

In tal caso, un riferimento const potrebbe essere migliore. Quando si utilizza un tale functor in algoritmi standard come transform, è possibile avvolgerlo in una piccola classe che esegue l'indirizzamento indiretto tramite un puntatore, per assicurarsi che rimanga economico da copiare.

Prendere un riferimento non const è potenzialmente fastidioso per gli utenti, poiché impedisce loro di passare in provvisori.

Problemi correlati