C++ overhead `function`


Esempio

std::function può causare un overhead significativo. Poiché std::function ha [valore semantica] [1], deve copiare o spostare il dato callable in se stesso. Ma dal momento che può assumere callable di tipo arbitrario, spesso è necessario allocare la memoria in modo dinamico per farlo.

Alcune implementazioni di function hanno il cosiddetto "ottimizzazione di piccoli oggetti", dove piccoli tipi (come puntatori di funzioni, puntatori di membri o funtori con uno stato molto piccolo) saranno memorizzati direttamente nell'oggetto function . Ma anche questo funziona solo se il tipo non è noexcept . Inoltre, lo standard C ++ non richiede che tutte le implementazioni ne forniscano una.

Considera quanto segue:

//Header file
using MyPredicate = std::function<bool(const MyValue &, const MyValue &)>;

void SortMyContainer(MyContainer &C, const MyPredicate &pred);

//Source file
void SortMyContainer(MyContainer &C, const MyPredicate &pred)
{
    std::sort(C.begin(), C.end(), pred);
}

Un parametro template sarebbe la soluzione preferita per SortMyContainer , ma supponiamo che questo non sia possibile o desiderabile per qualsiasi motivo. SortMyContainer non ha bisogno di memorizzare pred oltre la propria chiamata. Eppure, pred può ben allocare memoria se il funtore che gli viene dato è di una dimensione non banale.

function alloca la memoria perché ha bisogno di qualcosa da copiare / spostare; function assume la proprietà del chiamabile. Ma SortMyContainer non ha bisogno di possedere il callable; lo sta solo facendo riferimento. Quindi usare la function qui è eccessivo; potrebbe essere efficiente, ma potrebbe non farlo.

Non esiste un tipo di funzione di libreria standard che si riferisca semplicemente a un callable. Quindi dovrà essere trovata una soluzione alternativa, oppure puoi scegliere di vivere con il sovraccarico.

Inoltre, la function non ha mezzi efficaci per controllare da dove provengono le allocazioni di memoria per l'oggetto. Sì, ha costruttori che accettano un allocator , ma [molte implementazioni non le implementano correttamente ... o addirittura affatto ] [2].

C ++ 17

I costruttori di function che prendono un allocator non fanno più parte del tipo. Pertanto, non è possibile gestire l'allocazione.

Chiamare una function è anche più lento di chiamare direttamente i contenuti. Poiché qualsiasi istanza di function può contenere un chiamabile, la chiamata attraverso una function deve essere indiretta. L'overhead della function di chiamata è nell'ordine di una chiamata di funzione virtuale.