10
votes

G ++: STD :: Fonction initialisée avec type de fermeture utilise toujours une allocation de tas?

Certaines sources sur les internets (spécifiquement Celui-ci ) dit que STD :: Fonction utilise de petites optimisations de fermeture, par exemple Il n'allocoue pas le tas si la taille de la fermeture est inférieure à une certaine quantité de données (le lien ci-dessus indique 16 octets pour GCC)

donc je suis allé creuser via g ++ en-têtes p>

semble si une telle optimisation est appliquée ou non est décidé par ce bloc de code dans l'en-tête "fonctionnel" (g ++ 4.6.3) p> xxx pré>

et certaines lignes vers le bas: p> xxx pré>

EG Si _Local_storage () est vrai_type, que le placement nouveau-nouveau est appelé, sinon, neuf régulière p>

La définition de _Local_storage est le suivi: p>

max stored locally size: 16, align: 8
lambda size: 1
lambda align: 1
stored locally: false


1 commentaires

Je confirme vos résultats de ce programme: ideone.com/kzae6u Vous pouvez vérifier sur Clang ( melpon.org/wandbox ) que le même programme n'attribuait que la mémoire de mémoire pour une très grande capture ...


3 Réponses :


1
votes

STD :: L'attribution de la fonction est un détail de mise en œuvre; Enfin, j'ai vérifié que 12 octets est la taille du fonctionnement maximal de MSVC, 16 pour GCC, 24 pour Boost + MSVC.


1 commentaires

ADZM: Oui, cela est mentionné dans le lien au début de la question. Cependant, je ne vois pas que c'est en fait le cas avec g ++



2
votes

Je parie si vous avez ajouté ceci: xxx

vous recevrez: xxx

au moins c'est ce que Ideone dit .


2 commentaires

Oui, c'est à peu près implique de mon test. Question est: c'est final? Dr. Dobbs a tort et nous avons toujours des allocations de tas?


@Alexi., Cela dépend vraiment du compilateur.



7
votes

AS de GCC 4.8.1, la Fonction STD :: Fonction de LibstDC ++ Optimise uniquement les pointeurs aux fonctions et aux méthodes. Donc, quelle que soit la taille de votre foncteur (Lambdas incluse), l'initialisation d'une STD :: fonction de celui-ci déclenche une allocation de tas. Malheureusement, il n'y a pas de support pour les allocateurs personnalisés non plus.

Visual C ++ 2012 et LLVM LIBC ++ permettent d'attribuer l'allocation pour tout fonceur suffisamment petit. P>

Remarque, pour cette optimisation de votre ampleur de votre ameublement devrait remplir STD :: is_nothrow_move_constructible. Ceci est pour supporter noexcept std :: Fonction :: Swap (). Heureusement, Lambdas satisfait à cette exigence si toutes les valeurs capturées font. P>

Vous pouvez écrire un programme simple pour vérifier le comportement sur divers compilateurs: P>

#include <functional>
#include <iostream>

// noexpect missing in MSVC11
#ifdef _MSC_VER
# define NOEXCEPT
#else
# define NOEXCEPT noexcept
#endif

struct A
{
    A() { }
    A(const A&) { }
    A(A&& other) NOEXCEPT { std::cout << "A(A&&)\n"; }

    void operator()() const { std::cout << "A()\n"; }

    char data[FUNCTOR_SIZE];
};

int main()
{
    std::function<void ()> f((A()));
    f();

    // prints "A(A&&)" if small functor optimization employed
    auto f2 = std::move(f); 

    return 0;
}


0 commentaires