2016-11-11 76 views
1

我遇到了一些误导性问题。我有一个函数,它将字符串作为参考,使用正则表达式分割它,将一个部分保存回给定的字符串并返回另一个。然而,将一个匹配分配给引用参数似乎会使匹配对象无效(看起来像是一种错误的移动赋值),而将其分配给局部变量则可以正常工作。下面的代码:分配参考参数使对象无效

std::string ParseVar(std::string & szExp) 
{ 
    static std::regex oRegex("^([[:alpha:]][[:alnum:]_]*)\\s*<-\\s*(.+)$"); 
    std::smatch oMatch; 

    if (std::regex_match(szExp, oMatch, oRegex)) 
    { 
     if (oMatch.size() != 3) 
      throw std::runtime_error("internal error"); 

     std::cout << "Match before: " << oMatch.str(2) << std::endl; 
     szExp = oMatch.str(2); 
     std::cout << "Match after: " << oMatch.str(2) << std::endl; 
     return oMatch.str(1); 
    } 

    return ""; 
} 

此照片(用于szExp = “富< - 5 + 5 + 5 + 5”):

Match before: 5+5+5+5 
Match after: +5+5+5 

返回值也似乎被打破,但szExp包含适当的串。

将其更改为:

std::string ParseVar(std::string & szExp) 
{ 
    static std::regex oRegex("^([[:alpha:]][[:alnum:]_]*)\\s*<-\\s*(.+)$"); 
    std::smatch oMatch; 
    std::string save1, save2; 

    if (std::regex_match(szExp, oMatch, oRegex)) 
    { 
     if (oMatch.size() != 3) 
      throw std::runtime_error("internal error"); 

     save1 = oMatch.str(1); 
     save2 = oMatch.str(2); 

     std::cout << "Match before: " << oMatch.str(2) << std::endl; 
     szExp = save2; 
     std::cout << "Match after: " << oMatch.str(2) << std::endl; 
     return save1; 
    } 

    return ""; 
} 

打印同样的事情,但至少都返回值和szExp的罚款。

这是怎么回事吗?

回答

1

std::smatch对象是std::match_results模板的实例。它在cppreference上的条目包含以下段落:

这是一个专门的分配器感知容器。它只能是 默认创建,从std :: regex_iterator获取,或者由 std :: regex_search或std :: regex_match修改。由于std :: match_results 包含std :: sub_matches,其中每个匹配的 匹配的原始字符序列中有一对迭代器,它的未定义行为 检查std :: match_results,如果原始字符序列是 已销毁或迭代器由于其他原因而失效

因为修改原始字符串(这是你被分配到到szExp做什么)无效迭代器的字符序列,你属于以上并造成未定义行为的犯规。

+0

@PKua是将字符串复制到保存变量确实使完全独立的副本。然而,它不是你要输出的那些副本 - 而是你再次调用oMatch.str()(在你的'std :: cout'行) – Smeeheey

+0

需要记住的是oMatch依然依赖于' szExp'的整个生命周期。任何对'oMatch.str()'的调用都会产生一个独立的字符串,但后来的重复调用仍然需要'szExp'不会失效 – Smeeheey

+0

我注意到szExp是我的原始字符串,因此在发布评论后修改它会使迭代器失效,所以我删除了它(因为问题在你回答后实际上很愚蠢)。 对于那些将来会阅读它的人来说:评论中的问题是“do'oMatch.str()'创建原始字符串的尖头部分的副本吗?”。 无论如何,现在我可以(希望)了解一切。非常感谢。 – PKua