为什么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()
,因为我正在使用虚拟路径,而且我绝对不希望对任何文件系统进行任何调用。
为什么我的代码崩溃? 如何使其按预期工作?
答
这条线是未定义的行为,因为它在将访问被未测序相对于彼此的上下文访问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
,而不是将这些数字相迭代器。
https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom – user0042
使用'--i'和'我在同一个语句+ 2'是自找麻烦。更不用说'i + 2'可能超出范围,并且函数参数的评估顺序未指定。 –
@ user0042 std :: remove似乎是用于删除具有特定值的元素,但我想要删除具有特定索引的元素。 –