Ошибка Visual Studio regex_iterator?

Я работаю в Visual Studio 2013 и вижу то, что считаю ошибкой, я надеялся, что кто-нибудь подтвердит?

string foo{ "A\nB\rC\n\r" };
vector<string> bar;

for (sregex_iterator i(foo.cbegin(), foo.cend(), regex("(.*)[\n\r]{1,2}")); i != sregex_iterator(); ++i){
    bar.push_back(i->operator[](1).str());
}

Этот код попадает в Debug Assertion в библиотеке регулярных выражений Visual Studio:

regex_iterator осиротел

Если я определяю regex вне цикла for, все в порядке:

string foo{ "A\nB\rC\n\r" };
vector<string> bar;
regex bug("(.*)[\n\r]{1,2}");

for (sregex_iterator i(foo.cbegin(), foo.cend(), bug); i != sregex_iterator(); ++i){
    bar.push_back(i->operator[](1).str());
}

В качестве альтернативы это отлично работает в преобразовании, как показано в этом вопросе:

string foo{ "A\nB\rC\n\r" };
vector<string> bar;

// This puts {"A", "B", "C"} into bar
transform(sregex_iterator(foo.cbegin(), foo.cend(), regex("(.*)[\n\r]{1,2}")), sregex_iterator(), back_inserter(bar), [](const smatch& i){ return i[1].str(); });

Кто-нибудь может подтвердить, что это ошибка?


person Jonathan Mee    schedule 27.04.2015    source источник


Ответы (2)


В С++ 11 вам разрешено привязывать временное regex к const regex &, что может привести к неопределенному поведению, если итератор используется вне времени жизни временного объекта, поскольку он будет хранить указатель на него. Это дефект спецификации, а не ошибка, хотя Visual Studio улавливает это с помощью подтверждения отладки.

sregex_iterator i(foo.cbegin(), foo.cend(), regex("(.*)[\n\r]{1,2}"))
                                            ^^^^^
                                            temporary

Следующая удаленная перегрузка добавлялась в С++ 14, чтобы предотвратить этот случай, из cppreference< /а>:

regex_iterator(BidirIt, BidirIt,
           const regex_type&&,
           std::regex_constants::match_flag_type =
           std::regex_constants::match_default) = delete;       (since C++14)

и он говорит:

Перегрузку 2 нельзя вызывать с временным регулярным выражением, так как возвращенный итератор будет немедленно признан недействительным.

Так что это не ошибка Visual Studio, поскольку она реализует стандарт C++11, и это не было устранено в отчете о дефекте до более позднего времени. И clang, и gcc при использовании -std=c++14 или более поздних версий вызовут ошибку при первом (просмотре в реальном времени) и третий (посмотреть вживую) пример . Visual Studio только начала поддерживать некоторые C++14 в VS 2015:

[...] и первоначальная поддержка некоторых функций C++14.[...]

Мы видим, что дефект LWG 2332: regex_iterator/regex_token_iterator следует запретить временные регулярные выражения, имеет дело с этим:

Пользователи могут написать "for(sregex_iterator i(s.begin(), s.end(), regex("мяу")), end; i != end; ++i)", привязывая временное регулярное выражение к const regex& и сохранение указателя на него. Это будет скомпилировано автоматически, вызывая неопределенное поведение во время выполнения. Теперь у нас есть технология, предотвращающая компиляцию, например, как reference_wrapper отказывается привязываться к временным файлам.

Как Т.С. указывает, что последний пример, который вы показываете, на самом деле в порядке, даже если вы привязываете временное время его жизни до конца выражения.

person Shafik Yaghmour    schedule 27.04.2015
comment
Так вы говорите, что тот факт, что он скомпилирован, является ошибкой? А то, что я мог сделать оператор transform, это ошибка? - person Jonathan Mee; 27.04.2015
comment
@JonathanMee: тот факт, что он скомпилирован, означает, что VS 2013 в основном пытается реализовать C++ 11, а не C++ 14. Тот факт, что transform сработал, на самом деле не является ошибкой. Вы использовали временную после того, как она была уничтожена. Это неопределенное поведение, поэтому компилятор может делать все что угодно и при этом соответствовать стандарту. - person Jerry Coffin; 27.04.2015
comment
@JerryCoffin Интересно, я думаю, это проблема неполной поддержки какого-либо стандарта. Я, конечно, предполагал, что конструктор перемещения будет висеть на regex. - person Jonathan Mee; 27.04.2015
comment
Когда вы говорите: Поведение для случаев 1 и 3. Вы говорите о regex_iterator, которые были созданы путем перемещения regex вправо? Я до сих пор не понимаю, почему я не получил ошибку времени компиляции, поскольку это были deleted, если только предложение @JerryCoffin не является проблемой. Если это так, может быть, вы могли бы добавить примечание в свой ответ? - person Jonathan Mee; 27.04.2015
comment
@JonathanMee обновил, как я понял, было непонятно несколько моментов. - person Shafik Yaghmour; 27.04.2015
comment
@JonathanMee - обратите внимание, что Microsoft сообщила о LWG2332, когда проблема была обнаружена. И это было после выпуска VS2013. Что ты можешь сделать? - person Bo Persson; 27.04.2015
comment
@BoPersson Откуда мы знаем, что ошибка была отправлена ​​​​Майкрософтом? Я имею в виду, что это вряд ли было отправлено gcc, учитывая их медлительность в реализации regex, но все же... - person Jonathan Mee; 27.04.2015
comment
@JonathanMee STL (Стефан Т. Лававей) работает в MS и принимает активное участие в комитете. - person Shafik Yaghmour; 27.04.2015
comment
@ShafikYaghmour STL в данном случае относится к Стефану Т. Лававею, я уверен ... или вы пошутили. Я чувствую, что вы, ребята, намного круче меня... вы знакомы с ребятами, создающими компиляторы! - person Jonathan Mee; 27.04.2015
comment
@JonathanMee Я просто гик, и я внимательно слежу за C ++, он хорошо известен как STL, и это также его идентификатор на Reddit, и он активен там в потоках C ++. - person Shafik Yaghmour; 27.04.2015
comment
@JerryCoffin Версия transform в порядке (отчасти случайно); временное регулярное выражение не уничтожается до конца полного выражения, т. е. ;, после завершения вызова transform. - person T.C.; 27.04.2015
comment
@T.C.: Ах, хороший момент - если бы я думал, я бы это понял. - person Jerry Coffin; 27.04.2015

Нет, это не ошибка. См. LWG 2329 regex_match()/regex_search() с match_results должен запрещать временные строки. Эта конструкция демонстрирует неопределенное поведение, так как она привязывает временное регулярное выражение к const regex& и сохраняет указатель на него.

См. также Функции C++14 STL, исправления и критические изменения в Visual Studio 14 CTP1, где это указано как исправление.

person Marius Bancila    schedule 27.04.2015
comment
Обратите внимание, что LWG 2329 касается временных strings, не временных regexs. Вам нужен LWG 2332. Если реализация Visual Studio LWG 2332 действительно удалила конструктор move для regex, он не смог бы скомпилироваться. - person Jonathan Mee; 27.04.2015