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

时间:2017-09-04 20:16:55

标签: c++ string vector sigabrt erase

我的文件路径规范化函数有一个奇怪的问题我还没有完全理解并且修复有问题(我在C ++中也不是很老练)。

/**
 * 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;
}

它适用于大多数输入,但输入"/a/.."(应该返回"/")会使SIGABRT在指定行处崩溃。

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

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

为什么我的代码会崩溃? 如何让它按预期工作?

1 个答案:

答案 0 :(得分:1)

此行具有未定义的行为,因为它在访问未相互依赖的上下文中访问i两次:

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

由于评估顺序未指定,并且应用副作用的顺序未知,segments.begin() + (i+2)可以在向量结束时评估为迭代器。

您可以使用i的值而无需预先减少,并在从--返回后应用erase来解决此问题:

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

注意:以上代码使用std::next而不是向迭代器添加数字。