【问题标题】:Constraints on the lifetime of the argument to std::regex_match (and std::regex_search)对 std::regex_match(和 std::regex_search)的参数生命周期的约束
【发布时间】:2012-08-16 16:52:30
【问题描述】:

考虑带有签名者std::regex_match( std::string const&, std::smatch& match, std::regex const& re )的C++11函数,什么 是对第一个参数的生命周期的限制吗?我没找到 任何,但是当我执行以下程序时(使用 VC++ 2010 编译, 迭代器调试激活):

int
main()
{
    std::string a("aaa");
    std::string c("ccc");
    std::regex re("aaa(.*)ccc");
    std::smatch m;
    if (std::regex_match(a + "xyz" + c, m, re)) {
        std::cout << m[0] << std::endl;
        std::cout << m[1] << std::endl;
    }
    return 0;
}

它崩溃了,可能是因为m 中的sub_match 只保留 迭代器进入字符串,而不是副本。我在里面找不到任何东西 禁止我的代码的标准。

FWIW:它在 boost::regex 中也不起作用,这就是 std::regex 是基于。 (当然,Boost 没有记录任何 寿命方面的限制。)

最后,我想我的问题是:我应该发送 DR 到 标准组织,还是向 Microsoft 报告错误?

【问题讨论】:

  • 我会发送 DR。现在,DR 中应该包含的内容是另一个问题。选项将只是记录或提供采用右值引用的重载,以便 看起来 正确的简单代码行为正确。 [我倾向于采用文档方法]
  • @DavidRodríguez-dribeas 在什么基础上?标准中有很多函数需要引用,所需的生命周期永远不会超过函数本身。我们基于什么(除了 Boost 所做的)假设这不是这里的意图?
  • 好的,所以你说这可能是实现中的一个错误,并且标准可能被设计为复制参数。是的,这是第三种方法:)
  • @DavidRodríguez-dribeas 是的。我说我不知道​​意图是什么。皮特的回答表明委员会没有考虑到这个问题,所以没有明确的意图。这意味着他们下次会讨论并做出决定。

标签: c++ c++11


【解决方案1】:

我不记得在采用tr1::regexstd::regex 期间对这种可能性进行过任何讨论,所以我认为它根本没有被考虑。事后看来,这当然是一个我们应该预见到的陷阱。在我的脑海中,采用std::string&amp;&amp; 的重载将表明涉及临时性,并且需要一个副本。所以我会向标准委员会报告。 (完全披露:我编写了 Dinkumware 实现,这是微软发布的)

【讨论】:

  • 你可能基于 Boost,它有同样的问题(包括缺乏关于任何要求的文档)。通常不会出现问题,因为您通常不会尝试匹配临时人员。 (另一方面,我可以很容易地看到匹配循环的本地字符串,smatch 在循环外,并在循环结束后使用。)
  • @JamesKanze - 它不是基于 Boost。只是在这方面缺乏远见。
【解决方案2】:

regex_match 重载的规范指出 (28.11.2[re.alg.match]/6):

返回: regex_match(s.begin(), s.end(), m, e, flags)

对这个重载没有额外的要求,它委托的重载只需要一个迭代器范围——它没有办法让临时字符串保持活动状态,因为它甚至不知道有一个字符串保持活力。

STL'sregex presentation at C++Now '12 期间讨论过这个问题。有人建议可以在规范中添加额外的重载,以捕获右值字符串参数(例如basic_string&lt;...&gt;&amp;&amp;),这将给出一个很好的编译错误而不是这个运行时错误。不过,库规范不包括这些重载,而且我没有看到关于此的缺陷报告。

【讨论】:

  • 问题不仅仅在于右值。考虑一个在循环外声明的smatch,并在循环内调用regex_match,并在循环内定义一个字符串。问题很复杂:它可以工作(通过在匹配的情况下保留字符串的副本),因此可能需要它工作。
  • @JamesKanze - 好点。但是这意味着该库通常无法检测到这个生命周期问题。保留字符串的副本非常重要,所以我现在倾向于保持原样,并告诉人们“不要那样做”。但是,当然,我不代表委员会发言。
  • @JamesKanze:我看不出这与编译时无法检测到的其他生命周期问题有何不同:{ std::vector&lt;int&gt; v; return v.begin(); } 是格式良好的代码,无法检测(在所有情况)返回的迭代器在函数返回后失效。至少删除的右值重载将有助于检测明显的误用。在我看来,match_results 已经被充分指定:它只处理迭代器,这很好地表明人们应该注意它们指向的范围的生命周期。
  • @PeteBecker 我认为限制生命周期是一个有效的选择(因为没有限制它);如果这是委员会的决定,我当然可以接受。但如果有这样的约束,它必须是显式的。 (这与 James 的另一个示例不同,在该示例中,您将迭代器显式操作到集合中。我认为这里的标准很明确:在集合不再存在后使用迭代器是未定义的行为。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-02-07
  • 1970-01-01
  • 2017-06-18
  • 1970-01-01
  • 2013-02-23
  • 1970-01-01
相关资源
最近更新 更多