182 votes

Pourquoi peuvent-elles être mieux optimisé par le compilateur que la plaine fonctions?

Dans son livre, The C++ Standard Library (Second Edition) Nicolai Josuttis stipule que les lambdas peut être optimisé par le compilateur que la plaine fonctions.

En outre, les compilateurs C++ optimiser les lambdas mieux que ce qu'ils ne fonctions ordinaires. (Page 213)

Pourquoi est-ce?

Je pensais que quand il s'agit de l'in-lining, il ne devrait pas y avoir de différence. La seule raison pour laquelle je pense que les compilateurs pourraient avoir un meilleur contexte local avec des lambdas et peut faire plus d'hypothèses et d'effectuer plus d'optimisations.

187voto

Konrad Rudolph Points 231505

La raison en est que les lambdas sont fonction des objets afin de les transmettre à un modèle de fonction pour instancier une nouvelle fonction spécifiquement pour cet objet. Le compilateur peut donc trivialement inline le lambda appel.

Pour les fonctions, d'autre part, la vieille mise en garde s'applique: une fonction de pointeur est transmis à la fonction de modèle, et les compilateurs, traditionnellement, ont beaucoup de problèmes d'inlining des appels via des pointeurs de fonction. Ils peuvent théoriquement être inline, mais seulement si l'environnement de la fonction est incorporé.

Par exemple, considérons la fonction suivante template:

template <typename Iter, typename F>
void map(Iter begin, Iter end, F f) {
    for (; begin != end; ++begin)
        *begin = f(*begin);
}

Appelant avec un lambda comme ceci:

int a[] = { 1, 2, 3, 4 };
map(begin(a), end(a), [](int n) { return n * 2; });

Les résultats de cette instanciation (créé par le compilateur):

template <>
void map<int*, _some_lambda_type>(int* begin, int* end, _some_lambda_type f) {
    for (; begin != end; ++begin)
        *begin = f.operator()(*begin);
}

... le compilateur connaît _some_lambda_type::operator () et peut inline appels à trivialement. (Et de l'invocation de la fonction map avec tout les autres lambda de créer une nouvelle instanciation d' map depuis chaque lambda a un type distinct.)

Mais lorsqu'elle est appelée avec un pointeur de fonction, l'instanciation se fait comme suit:

template <>
void map<int*, int (*)(int)>(int* begin, int* end, int (*f)(int)) {
    for (; begin != end; ++begin)
        *begin = f(*begin);
}

... et ici, f de points à une adresse différente pour chaque appel à l' map , et donc le compilateur ne peut pas inline appels d' f moins que les environs appel à l' map a également été insérée pour que le compilateur puisse résoudre f à une fonction spécifique.

28voto

jcoder Points 14982

Parce que quand vous passez à une "fonction" d'un algorithme, vous êtes en fait en passant un pointeur de fonction de sorte qu'il a à faire, un appel indirect via le pointeur à la fonction. Lorsque vous utilisez un lambda vous êtes de passage dans un objet à un modèle spécialement instancié pour que le type et l'appel à la fonction lambda est un appel direct, pas un appel à l'aide d'un pointeur de fonction peut donc beaucoup plus susceptibles d'être insérée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X