为什么vector.erase()会遇到SIGABRT?

为什么vector.erase()会遇到SIGABRT?

问题描述:

我的文件路径规范化函数有一个奇怪的问题我不完全理解,并且无法修复(我在C++中也不是很成熟)。为什么vector.erase()会遇到SIGABRT?

/** 
* Converts any path (e.g. /a/d/../b/.//c/) to absolute /a/b/c format. 
* @param path Any valid path beginning with/
* @return Path in absolute /a/b/c format. 
*/ 
static std::string normalizePath(std::string path) 
{ 
    if (path == "/") 
     return "/"; 

    if (path[0] != '/') // full relative paths not supported due to lack of context 
     return ""; 

    std::vector<std::string> segments = strsplit(path, '/'); 
    while (segments[0] == "." || segments[0] == "..") 
     segments.erase(segments.begin()); 

    for (int i = 0; i < segments.size(); i++) 
    { 
     if (segments[i] == "." || segments[i].empty()) 
      segments.erase(segments.begin() + (i--)); 
     else if (segments[i] == "..") 
      segments.erase(segments.begin() + (--i), segments.begin() + (i+2)); // SIGABRT 
    } 

    std::string r; 
    for (int i = 0; i < segments.size(); i++) 
     r += "/" + segments[i]; 

    return r; 
} 

它正常工作与大多数的投入,但投入"https://*.com/a/.."(这应该返回"/")使得它在指定的符合SIGABRT崩溃。

我的理解是,我删除了当前和以前的元素,但显然这种假设是错误的。

我也不愿意只使用realpath(),因为我正在使用虚拟路径,而且我绝对不希望对任何文件系统进行任何调用。

为什么我的代码崩溃? 如何使其按预期工作?

+2

https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom – user0042

+1

使用'--i'和'我在同一个语句+ 2'是自找麻烦。更不用说'i + 2'可能超出范围,并且函数参数的评估顺序未指定。 –

+1

@ user0042 std :: remove似乎是用于删除具有特定值的元素,但我想要删除具有特定索引的元素。 –

这条线是未定义的行为,因为它在将访问被未测序相对于彼此的上下文访问i两次:

segments.erase(segments.begin() + (--i), segments.begin() + (i+2)); 

由于评价的顺序是不确定的,并且施加侧的顺序效果未知,segments.begin() + (i+2)可以评估为迭代器超过向量的末尾。

您可以从erase回国后通过使用i值,而不预减,并应用--解决这个问题:

else if (segments[i] == "..") { 
    segments.erase(std::next(segments.begin(), i-1), std::next(segments.begin(), i+1)); 
    --i; 
} 

注:上面的代码使用std::next,而不是将这些数字相迭代器。