不断擦除字符串会导致无限循环

Continually erasing a string leads to an infinite loop

我想做的是进入一条路径,然后逐个目录不断地擦除路径目录,随时检查它是否是符号 link。这是我拥有的:

static bool isLinkDirInSymLink (std::string linkPath)
    {
    DIR *baseDir;
    struct dirent *currentDir;

    do
        {
        baseDir = opendir(linkPath.c_str());
        if (baseDir)
            {
            currentDir = readdir(baseDir);
            if (currentDir->d_type == DT_LNK)
                return true;
            }
        linkPath.erase (linkPath.find_last_of("/") + 1, linkPath.find_first_of("[=10=]"));
        } while (strcmp(linkPath.c_str(), "") != 0);

    return false;
    }

这陷入了无限循环。当我 运行 gdb 中的程序时,我发送了一个 linkPath/home/user/test/linktest/out/mDirs/testDir1/test,当它成功擦除后我剩下的是 /home/user/test/linktest/out/mDirs/testDir1,然而这是无限循环开始的地方。即使这与进入 erase 时的第一条路径格式相同,也没有任何反应。我尝试了 erasehere 的许多不同变体,但 none 似乎有效。我也试过 linkPath.append('[=18=]') 因为我认为最后可能是空字符的问题。

谢谢大家,这就是我最后的结果:

char realPath[MAX_FILELENGTH];

do
    {
    if (realpath (linkPath.c_str(), realPath) != NULL)
        if (strcmp(linkPath.c_str(), realPath) != 0)
            return true;

    size_t eraseFrom = linkPath.rfind('/');
    if (std::string::npos != eraseFrom)
        linkPath.erase(eraseFrom);
    } while ( !linkPath.empty() );

return false;
linkPath.find_last_of("/") + 1

应该就是;

linkPath.find_last_of("/")

第一次擦除会留下尾随 /,因此下一次擦除会尝试从字符串的末尾擦除到末尾,因此循环。擦除应包括目录分隔符 /.

不需要linkPath.find_first_of("[=14=]"),直接用npos删除到字符串末尾即可。 find_first_of 的使用给出了大小类型的结果,因此使用了以下形式的擦除 basic_string& erase( size_type index = 0, size_type count = npos );.

由于您在擦除调用中使用了 + 1,因此您正在擦除从 / 到字符串结尾之前的字符,擦除以下字符:

/home/user/test/linktest/out/mDirs/testDir1/test[=10=]
                                            ^^^^

循环的第一次迭代将删除 test,留下 /home/user/test/linktest/out/mDirs/testDir1/。所有对 erase 的后续调用都不会执行任何操作,因为 /[=17=].

之间有零个字符

您应该在擦除调用中从 linkPath.find_last_of("/") + 1 中删除 + 1,这样结尾的斜线也会被删除。

此外,erase(size_t, size_t) 重载实际上将要擦除的部分的 长度 作为第二个参数 - find_first_of returns 索引找到的字符,而不是它的迭代器。您的代码仅在偶然情况下起作用。使用 std::string::npos,这将清除所有内容直到结束,而不是 [=17=] 字符的位置(如果您尚未调用 c_str(),则该字符可能不存在于字符串中)。

我猜你在查看调试器时漏掉了结尾的斜杠。这可能会更好:

linkPath.erase (linkPath.begin()+linkPath.find_last_of("/"), linkPath.end());

另一个问题是 std::string::erase 的错误重载被调用:#1 in this list ("pos+len"), while you likely intended #3 ("range"). That happens because std::string::find_last_of returns size_t,不是迭代器。或者,为了节省打字时间,您可以使用:

linkPath.resize(linkPath.find_last_of("/"));

我认为你的意思如下

#include <iostream>
#include <string>

int main()
{
    std::string linkPath( ""
                          "continually-erasing-string-leads-to-infinite-loop" );

    do
    {
        std::cout << linkPath << std::endl;

        auto n = linkPath.rfind( '/' );
        n = n == std::string::npos ? 0 : n;

        linkPath.erase( n );
    } while ( !linkPath.empty() );        
}    

程序输出为

continually-erasing-string-leads-to-infinite-loop

http://whosebug.com/questions
http://whosebug.com
http:/
http:

当然你可以随意修改代码。它演示了完成任务的方法。

至于你的代码那么这个调用

linkPath.find_first_of("[=12=]")

将永远 return std::string::npos。所以它没有男性的意义。 并使用这个表达式

linkPath.find_last_of("/") + 1

将始终保留字符串中第一个找到的字符“/”。

更正确和简化的实现

static bool isLinkDirInSymLink(std::string linkPath) {
    DIR * baseDir;
    struct dirent * currentDir;
    do {
        baseDir = opendir(linkPath.c_str());
        if (baseDir) {
            currentDir = readdir(baseDir);
            if (currentDir->d_type == DT_LNK) return true;
        }
        std::string::size_type it = linkPath.rfind('/');
        if (it != std::string::npos) linkPath.erase(it);
    } while (!linkPath.empty());
    return false;
}