我在ideone和Coliru上发布了以下代码:
#include <iostream>
#include <regex>
#include <string>
int main()
{
std::string example{" <match1> <match2> <match3>"};
std::regex re{"<([^>]+)>"};
std::regex_token_iterator<std::string::iterator> it{example.begin(), example.end(), re, 1};
decltype(it) end{};
while (it != end) std::cout << *it++ << std::endl;
return 0;
}
两个站点都使用 GCC 4.9.2。我不知道 ideone 使用什么编译参数,但在 Coliru 中没有什么不寻常的。
Coliru 没有给我match1
结果:
科里鲁
# g++ -v 2>&1 | grep version;
# g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
gcc version 4.9.2 (GCC)
match2
match3
ideone(顺便说一下,Coliru的clang 3.5.0使用libc++)
match1
match2
match3
我的代码是否有未定义的行为或其他东西?什么原因可能导致这种情况?
libstdc++的regex_token_iterator
复制构造函数中的一个错误,由postincrement运算符调用。 该错误已于 2014 年 12 月修复;此后发布的 GCC 4.9 和 5.x 版本将具有修复程序。该 bug 的本质是迭代器的副本为副本的目标提供别名,从而导致观察到的行为。
解决方法是使用预增量 - 从微优化的角度来看,这也是可取的,因为regex_token_iterator
是一个相当重的类:
for (; it != end; ++it) std::cout << *it << std::endl;
代码有效。
唯一合理的解释是标准库版本不同;尽管在大多数情况下,标准库实现都随编译器一起提供,但它们可以通过Linux包管理器进行独立升级。
在这种情况下,这似乎是去年年底修复的libstdc++错误:
- 科里鲁有
__GLIBCXX__ == 20141030
- Ideone有
__GLIBCXX__ == 20141220
我能找到的 Bugzilla 上最有可能的匹配项是 bug 63497,但老实说,我不相信这个特定的错误曾经被 Bugzilla 完全覆盖过。约瑟夫·曼斯菲尔德(Joseph Mansfield)发现,在这种特定情况下,这些特定症状至少是由修复后增量触发的。