boost :: any_range <gsl :: string_span > crash en mode Release

J’observe un comportement plutôt étrange du code suivant:

#include  #include  #include  #include  #include  #include "gsl.h" template  using ImmutableValueRange = boost::any_range; template  ImmutableValueRange make_transforming_immutable_range(const C& container) { return container | boost::adaptors::transformed([](const typename C::value_type& v) -> T { //std::cout << "trans : " << T{ v }.data() << "\n"; return T{ v }; }); } void f(ImmutableValueRange<gsl::cstring_span> r) { for (const auto& c : r) { std::cout << c.data() << "\n"; } } int main() { std::vector v({ "x", "y", "z" }); f(make_transforming_immutable_range<gsl::cstring_span>(v)); } 

L’idée ici est d’isoler la représentation réelle d’une séquence de chaînes reçue en tant que paramètre par la fonction f derrière un any_range et gsl::ssortingng_span (remarque, la validation qui modifie ssortingng_view en ssortingng_span a été effectuée il y a quelques heures). GSL).

Mon code d’origine ne any_range pas de paramètre de modèle const T as Reference pour any_range (il s’agissait d’un simple T ) et il s’est any_range pendant l’exécution. Cependant, cela ne se produisait qu’en mode Release et fonctionnait parfaitement dans Debug ou RelWithDebInfo (généré par CMake). J’ai utilisé VS2013 / 2015 x64. De plus, essayer de déboguer la version complète de la version Release, en ajoutant une sortie de débogage à la conversion, lambda a éliminé le plantage (je suppose que cela a empêché l’inline). Ma dernière solution de travail consiste à spécifier const T comme Reference .

Cependant, je me demande toujours pourquoi l’accident s’est-il produit en premier lieu? Est-ce le bug du compilateur VS? Bug dans l’implémentation actuelle de ssortingng_span ? Ou suis-je simplement en boost::any_range utiliser le boost::any_range ?

modifier

Vient de construire la version avec clang 3.7.0 et le comportement est similaire (fonctionne très bien en débogage et ne plante pas, mais génère des ordures sans const T avec -O2 ). Donc, cela ne semble pas être un problème de compilateur.

En fin de compte, la méthode de dereference any_range retournera une référence à T sauf si le type Reference est spécifié en tant que const T , créant ainsi une référence suspendue à une variable temporaire. Cela est dû à l’utilisation de any_incrementable_iterator_interface::mutable_reference_type_generator défini dans any_iterator_interface.hpp .

Par conséquent, la solution correcte au problème consiste en effet à spécifier const T comme type de Reference au cas où le déréférencement de l’iterator renvoie un temporaire.

Après un rapide coup d’œil, je soupçonne que le problème réside dans votre lambda. Si j’ai bien compris, vous finissez par prendre une référence std::ssortingng by const avec la déclaration de paramètre suivante:

const typename C::value_type& v

Cependant, vous utilisez ensuite v pour construire un cssortingng_span . Voici le cssortingng_span : cssortingng_span seulement un constructeur qui va d’une référence non-constante à un type de conteneur (comme std::ssortingng ). Conceptuellement, le constructeur ressemble à ceci:

template cssortingng_span(Cont& c)

Je suppose donc que lorsque vous revenez de votre lambda, un temporaire est créé à partir de v , puis transmis au constructeur cssortingng_span afin de fournir un argument de référence non-const. Bien sûr, une fois que ce temporaire est nettoyé, votre cssortingng_span est laissé en cssortingng_span .