2013-07-13 16 views
17

Ho appena letto il libro classico "Effective C++, 3rd Edition", e nell'articolo 20 l'autore conclude che i tipi incorporati , gli iteratori STL e gli oggetti funzione sono più appropriato per pass-by-value. Potrei ben capire il motivo per i tipi built-in e iterator, ma perché l'oggetto funzione dovrebbe essere pass-by-value, poiché sappiamo che è comunque di classe?perché gli oggetti funzione devono essere pass-by-value

+2

+1 per aver letto Effetto C++ – Borgleader

+0

Gli oggetti funzione raramente devono avere un sovraccarico. – chris

+0

Almeno, è più logico (tutti gli oggetti, in generale) ora che c'è la semantica del movimento. –

risposta

18

In un caso tipico, un oggetto funzione avrà poco o (più spesso) nessuno stato persistente. In tal caso, passare per valore potrebbe non richiedere in realtà alcun passaggio - il "valore" che viene passato è praticamente poco o nulla più di un segnaposto per "questo è l'oggetto".

Data la piccola quantità di codice in molti oggetti funzione, ciò porta ad un'ulteriore ottimizzazione: è spesso abbastanza facile per il compilatore espandere il codice per l'oggetto funzione in linea, quindi nessun parametro viene passato e nessuna chiamata di funzione è coinvolto a tutti.

Un compilatore può essere in grado di fare lo stesso quando si passa un puntatore o riferimento, invece, ma non è così facile - molto più comune che si ritroverà con un oggetto che viene creato, il suo indirizzo passato, e quindi la funzione chiama operatore per quell'oggetto che viene invocato tramite quel puntatore.

Modifica: Probabilmente vale anche la pena menzionare che lo stesso vale per i lambda, dal momento che sono in realtà solo oggetti funzione mascherati. Non si conosce il nome della classe, ma creano una classe nell'ambito immediatamente circostante che sovraccarica l'operatore della chiamata di funzione, che è ciò che viene invocato quando si "chiama" il lambda. [Grazie a @Mark Garcia.]

+0

Grazie per la spiegazione, e la parte "ottimizzazione in linea" mi impressiona molto. – JavaBeta

+1

La mia esperienza lavorativa mostra che l'ampio uso di 'boost :: bind' porta a oggetti funzione che sono costosi da copiare. Sembra aumentare in modo esponenziale la profondità del binding (vincolando un callback che ha richiamato la callback all'interno ecc.) –

1

Da efficace STL (poiché sembra che gli piaccia Scott Meyers) articolo 38 Design classi di funzionamento per pass-per-valore.

"In C e C++, i puntatori di funzione vengono passati per il valore STL Gli oggetti funzione vengono modellati dopo i puntatori di funzione, quindi la convenzione nell'STL è che anche gli oggetti funzione vengono passati per valore quando passano ae da funzioni. "

Questo ha alcuni vantaggi e alcune implicazioni, come ha detto @Jerry Coffin, il compilatore può fare alcune ottimizzazioni come inlining del codice per evitare chiamate di funzione Un buon esempio di questo caso è il confronto delle prestazioni qsort vs std :: sort, dove std :: sort usando i functors inline superano qsort di molto, potete trovare maggiori informazioni su questo su AWL efficace dove è discusso ampiamente e menzionato in diversi capitoli.

Anche questo ha diverse implicazioni, poiché gli oggetti funzione vengono passati e restituiti in base al valore, è necessario assicurarsi che l'oggetto disponga di meccanismi di copia ben definiti, di dimensioni ridotte (altrimenti potrebbe essere costoso) e monomorfico (dal momento che il passaggio di oggetti polimorfici in base al valore può causare l'affettamento di oggetti).

+0

Le serie efficaci di Meyers sono molto popolari in Cina :-). Inoltre, grazie per la spiegazione della differenza tra std :: sort e std :: qsort. – JavaBeta

4

Il motivo n. 1 per passare gli oggetti funzione in base al valore è perché la libreria standard richiede che gli oggetti funzione che si passano ai suoi algoritmi siano copiabili. C++ 11 §25.1/10:

[Nota: Se non diversamente specificato, gli algoritmi che prendono oggetti funzione come argomenti sono autorizzati a copiare quelle funzione oggetti liberamente. I programmatori per i quali l'identità dell'oggetto è importante dovrebbero prendere in considerazione l'utilizzo di una classe wrapper che punta a un oggetto di implementazione non protetto come reference_wrapper<T> (20.8.3), o una soluzione equivalente.-end note]

Le altre risposte fanno un ottimo lavoro di spiegazione della logica.

Problemi correlati