Visual Studio regex_iterator Bug?

Jon*_*Mee 8 c++ regex assertion c++11 visual-studio-2013

我在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());
}
Run Code Online (Sandbox Code Playgroud)

此代码命中Visual Studio regex库中的Debug Assertion:

regex_iterator

如果我定义regex外部for-loop就可以了:

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());
}
Run Code Online (Sandbox Code Playgroud)

或者,这可以在转换中正常工作,如此问题所示:

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(); });
Run Code Online (Sandbox Code Playgroud)

有人可以证实这是一个错误吗?

Sha*_*our 10

在C++ 11你被允许结合临时regexconst regex &如果迭代使用临时的寿命之外,因为这将存储指向它可导致未定义的行为.这是规范中的缺陷,虽然Visual Studio通过调试断言捕获了它,但它并不是错误.

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

以下删除的重载是在C++ 14中添加来防止这种情况,来自cppreference:

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

它说:

不允许使用临时正则表达式调用重载2,因为返回的迭代器将立即失效.

所以这不是一个Visual Studio错误,因为它正在实现C++ 11标准,直到后来才通过缺陷报告解决.无论clanggcc使用-std=c++14以上将产生你的第一个错误(见直播)和第三(见直播)的例子.Visual Studio仅开始支持VS 2015中的一些C++ 14 :

[...]并初步支持某些C++ 14功能.[...]

我们可以看到LWG缺陷2332:regex_iterator/regex_token_iterator应该禁止临时正则表达式处理:

用户可以写"for(sregex_iterator i(s.begin(),s.end(),regex("meow")),end; i!= end; ++ i)",将临时正则表达式绑定到const regex&存储指向它的指针.这将静默编译,在运行时触发未定义的行为.我们现在有了防止这种编译的技术,就像reference_wrapper拒绝绑定到temporaries一样.

正如TC指出你显示的最后一个例子实际上是好的,即使你绑定一个临时的,它的生命周期延伸到表达式的结尾.

  • @JonathanMee:它编译的意思是VS 2013主要尝试实现C++ 11,而不是C++ 14.`transform`工作的事实并不是一个真正的错误.你在销毁后使用了一个临时的.这是未定义的行为,因此编译器可以执行*任何*并仍然符合标准. (3认同)
  • @JonathanMee - 请注意,当发现问题时,Microsoft报告了LWG2332.这是*VS2013发布之后的*.你能做什么? (2认同)
  • @JonathanMee STL(Stephan T. Lavavej)在MS工作,并且非常参与委员会 (2认同)