2017-08-01 4 views
0

Le code suivant me donne un défaut de segmentation. Après le débogage, je découvre que le problème peut être résolu en déclarant le lambda comme auto plutôt que sur Function. Pourquoi est-ce le cas?Erreur de segmentation lors du stockage de lambda en tant que fonction std ::

#include <functional> 
#include <iostream> 
#include <vector> 

typedef std::vector<double> Vec; 
typedef std::function<const Vec&(Vec)> Function; 


int main() 
{ 
    //Function func = [](const Vec& a)->Vec /*this give me segfault*/ 
    auto func = [](const Vec& a)->Vec /*this work just fine??*/ 
     { 
       Vec b(2); 
       b[0] = a[0] + a[1]; 
       b[1] = a[0] - a[0]; 
       return b; 
     }; 
    Vec b = func(Vec{1,2}); 
    std::cout << b[0] << " " << b[1] << "\n"; 
    return 0; 
} 

Ce serait génial si je peux déclarer comme fonction parce que je voudrais passer cette expression lambda à d'autres classes.

L'erreur que j'ai quand func est déclarée comme fonction est:

Programme signal reçu SIGSEGV, Segmentation fault. 0x0000000000401896 dans std :: vector> :: size (this = 0x0) at /usr/include/c++/5/bits/stl_vector.h:655 655 {return taille_type (this -> _ M_impl._M_finish - this -> _ M_impl. _M_start); }
(gdb) backtrace
# 0 0x0000000000401896 dans std :: vector> :: size (ce = 0x0) à /usr/include/c++/5/bits/stl_vector.h:655
# 1 0x00000000004015aa dans std :: vector> :: vector (this = 0x7fffffffdc50, __x =) à /usr/include/c++/5/bits/stl_vector.h:320

# 2 0x0000000000400d12 dans main() à test.cxx: 18

Répondre

6

const Vec&(Vec) est équivalent à un lambda qui ressemble à ceci (Vec) -> const Vec&. Vous passez un (const Vec&) -> Vec.

std::function accepte en raison de la séquence d'appel contenant une conversion valide (Vous pouvez transmettre une valeur à une fonction attend une référence const).

L'erreur de segmentation est plus susceptible que le comportement indéfini inhérent à la valeur de retour de votre lambda (un temporaire) étant lié à une référence const dans std::functionoperator(); cette référence est renvoyée en dehors du std::function, ce qui en fait immédiatement une référence suspecte.

1

Vous devez faire attention aux types de fonctions, et cela devrait fonctionner correctement si vous utilisez le bon type; Peut-être que le problème devient plus clair avec moins d'encapsuleurs d'objets et de fonctions plus conventionnelles.

Qu'est-ce que cela se résume à, une fois que vous retirez la indirection à travers des objets, est la suivante:

// const Vec& -> Vec 
std::vector<double> the_lambda(const std::vector<double>& x) 
{ 
    return x; 
} 

// Vec -> const Vec& 
const std::vector<double>& the_function(std::vector<double> x) 
{ 
    return the_lambda(x); 
} 


int main() 
{ 
    std::vector<double> v = {1, 2}; 
    std::vector<double> lv = the_lambda(v); // OK. 
    std::vector<double> fv = the_function(v); // Undefined. 
} 

Cette compile, mais g ++ met en garde contre que the_function renvoie une référence à un temporaire, ce qui est exactement ce qui se passe avec le std::function (mais sans trop d'indice du compilateur).

(je suis assez convaincu que, si cette conversion de la valeur retournée dans std::function est une erreur. Vous ne vous en sortir avec si vous utilisez des pointeurs de fonction, et C++ est censé être plus sûr que C, pas moins.)