【问题标题】:Visual Studio regex_iterator Bug?Visual Studio regex_iterator 错误?
【发布时间】:2015-04-27 12:26:42
【问题描述】:

我在 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());
}

此代码在 Visual Studio 正则表达式库中遇到调试断言:

regex_iterator 孤儿

如果我在 for 循环之外定义 regex 就可以了:

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());
}

另外,这在this question 中所示的转换中也可以正常工作:

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(); });

有人可以确认这是一个错误吗?

【问题讨论】:

    标签: c++ regex c++11 visual-studio-2013 assertion


    【解决方案1】:

    在 C++11 中,您可以将临时 regex 绑定到 const regex &amp;,如果在临时生命周期之外使用迭代器,则可能导致未定义的行为,因为它将存储指向它的指针。这是规范中的一个缺陷,它不是错误,尽管 Visual Studio 使用调试断言捕获了这一点。

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

    在 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)
    

    它说:

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

    所以这不是 Visual Studio 错误,因为它正在实现 C++11 标准,直到后来才通过缺陷报告解决这个问题。 clanggcc 使用 -std=c++14 或更高版本都会在您的第一个 (see it live) 和第三个 (see it live) 示例中产生错误。 Visual Studio 在VS 2015 中才开始支持一些 C++14:

    [...]以及对某些 C++14 功能的初始支持。[...]

    我们可以看到LWG defect 2332: regex_iterator/regex_token_iterator should forbid temporary regexes 处理这个:

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

    作为 T.C.指出您展示的最后一个示例实际上是可以的,即使您正在绑定一个临时的,它的生命周期也会延长到表达式的末尾。

    【讨论】:

    • 那么你的意思是它编译的事实是一个错误?我可以执行transform 语句的事实是一个错误?
    • @JonathanMee:它编译的事实意味着 VS 2013 主要尝试实现 C++11,而不是 C++14。 transform 工作的事实并不是真正的错误。你在它被破坏后使用了一个临时的。那是未定义的行为,所以编译器可以做任何事情并且仍然符合标准。
    • @JonathanMee - 请注意,微软在发现问题时报告了 LWG2332。那是 VS2013 发布之后。你能做什么?
    • @JonathanMee STL(Stephan T. Lavavej) 在 MS 工作,非常参与委员会
    • @JonathanMee 我只是一个极客,我密切关注 C++,他被称为 STL,这也是他在 reddit 上的 id,他在那里活跃于 C++ 线程。
    【解决方案2】:

    不,这不是错误。见LWG 2329 regex_match()/regex_search() with match_results should forbid temporary strings。此构造表现出未定义的行为,因为它将临时正则表达式绑定到 const regex& 并存储指向它的指针。

    另请参阅C++14 STL Features, Fixes, And Breaking Changes In Visual Studio 14 CTP1,其中将其列为修复程序。

    【讨论】:

    • 请注意,LWG 2329 是关于临时 strings 不是临时 regexs。你要找的是LWG 2332。如果 Visual Studio 的 LWG 2332 实现真的删除了 move 的构造函数 regex 它应该无法编译。
    猜你喜欢
    • 1970-01-01
    • 2015-02-18
    • 2017-09-06
    • 2014-01-13
    • 2018-04-27
    • 2015-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多