32 votes

La référence de lvalue est devenue invalide après être passée par une fonction d'identité

Quelqu'un pourrait-il expliquer pourquoi la référence est devenue invalide après une fonction "identité", foo1 ? Une "adresse" vers A n'est-elle pas passée et renvoyée par foo1 ?

 struct A {
    A(int x) : x_(x) {}
    int x_;
};

int main() {

    function<const A&(const A& r)> foo1 = [](const A& r) { 
        return r;
    };

    vector<A> vec{1, 2, 3};
    cout << foo1(vec[0]).x_ << endl;   // RUNTIME ERROR

    return 0;
}
 

En quoi la ligne de problème diffère-t-elle de:

 const A& r = vec[0];
const A& r1 = r;
 

43voto

Barry Points 45207

Le problème, c'est votre lambda. Il ne fait pas ce que vous pensez que cela fonctionne:

function<const A&(const A& r)> foo1 = [](const A& r) { 
//                                               ~~~~~~
    return r;
};

Notez qu'il n'y a pas de fuite de type de retour. Cela signifie qu'il est automatiquement déduit. La déduction ne donne jamais de vous un type de référence, de sorte que cette lambda retourne un A, pas un A const&. Qui est revenu temporaire A est lié au rendement A const& de functions' operator(). Que temporaire n'est pas la durée de vie prolongée. Mais le temps de terminer l'appel foo1(),, nous avons une balançant de référence pour que temporaire A. C'est un comportement indéfini, qui, j'imagine, avec votre compilateur, vous a donné une utile d'erreur à l'exécution.

Pour résoudre ce problème, vous devez spécifier explicitement le type de retour:

function<const A&(const A& r)> foo1 = [](const A& r) -> A const& { 
    return r;
};

Mais même cela est dangereux, car vous pouvez toujours passer un temporaire A dans cette fonction et d'obtenir un bancales référence. Pas de véritable moyen de contourner cela.


La facilité de tomber dans ce piège est également LWG Question 2813

12voto

François Andrieux Points 16034

Bien que votre objet function renvoie const A& le lambda que vous fournissez ne le fait pas. Son type de retour est déduit de la déclaration de retour, qui est déduite de A . Essayez d’ajouter un type de retour explicite comme celui-ci.

 function<const A&(const A& r)> foo1 = [](const A& r) -> const A& { 
    return r;
};
 

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