Je voulais construire une vue sur toutes les sous-correspondances de regex
dans text
. Voici deux façons de définir une telle vue :
char const text[] = "Les adresses IP sont : 192.168.0.25 et 127.0.0.1";
std::regex regex{R"((\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3}))"};
auto sub_matches_view =
std::ranges::subrange(
std::cregex_iterator{std::ranges::begin(text), std::ranges::end(text), regex},
std::cregex_iterator{}
) |
std::views::join;
auto sub_matches_sv_view =
std::ranges::subrange(
std::cregex_iterator{std::ranges::begin(text), std::ranges::end(text), regex},
std::cregex_iterator{}
) |
std::views::join |
std::views::transform([](std::csub_match const& sub_match) -> std::string_view { return {sub_match.first, sub_match.second}; });
- La valeur de
sub_matches_view
eststd::csub_match
. Elle est créée en construisant d'abord une vue d'objetsstd::cmatch
(via l'itérateur regex), et puisque chaquestd::cmatch
est une série d'objetsstd::csub_match
, elle est aplatie avecstd::views::join
. - La valeur de
sub_matches_sv_view
eststd::string_view
. Elle est identique àsub_matches_view
, sauf qu'elle enveloppe également chaque élément desub_matches_view
dans unstd::string_view
.
Voici un exemple d'utilisation des plages ci-dessus :
for(auto const& sub_match : sub_matches_view) {
std::cout << std::string_view{sub_match.first, sub_match.second} << std::endl; // #1
}
for(auto const& sv : sub_matches_sv_view) {
std::cout << sv << std::endl; // #2
}
La boucle #1
fonctionne sans problèmes - les résultats imprimés sont corrects. Cependant, la boucle #2
provoque des problèmes de heap-use-after-free selon l'Address Sanitizer. En fait, simplement parcourir sub_matches_sv_view
sans accéder aux éléments cause également ce problème. Ici se trouve le code sur Compiler Explorer ainsi que le résultat de l'Address Sanitizer.
Je suis à court d'idées quant à l'endroit où se situe mon erreur. text
et regex
ne deviennent jamais hors de portée, je ne vois aucun itérateur qui pourrait être accédé en dehors de leur durée de vie. L'objet std::csub_match
contient des itérateurs (.first
, .second
) dans text
, donc je ne pense pas qu'il doive rester en vie lui-même après la construction du std::string_view
dans std::views::transform
.
Je sais qu'il existe de nombreuses autres façons d'itérer sur les correspondances regex, mais je suis spécifiquement intéressé par ce qui cause les bugs de mémoire dans mon programme, je n'ai pas besoin de contournements pour ce problème.