【问题标题】:C++ Vector removing specific items, but segfaultsC ++ Vector删除特定项目,但段错误
【发布时间】:2011-03-31 01:36:37
【问题描述】:

全部。我正在开发使用系统的主机文件来阻止广告的软件,但在代码上。

我有一个自定义类HostEntry,其中包含必要的信息,例如目标主机、要阻止的主机、目标主机的 ip...等。

在 HostsManager 类中,它保留一个向量来跟踪所有添加的主机。为了完全阻止主机,我必须添加example.comwww.example.com,但是当我遍历向量时,它只会删除以“www”开头的条目。留下一个没有。如果您再次尝试删除它(只有条目缺少“www.”),它会出现段错误,我不知道为什么。

void HostsManager::delHost(std::string blockedhost) {
    strip(blockedhost);
    string tmp; // yes I know it's not great practice to do it like this, but it was for debug reasons
    for (vector<HostEntry>::iterator viter = hosts.begin(); viter != hosts.end(); ++viter) {
        tmp = viter->getHost();
        if (tmp == blockedhost || tmp == ("www." + blockedhost)) {
            viter = hosts.erase(viter);
        }
    }
}

对该特定函数的示例调用:

HostsManager mgr;
mgr.delHost("mysite.com"); // this deletes "www.mysite.com" but not "mysite.com" - whether or not you call delHost() with the "www." prefix
mgr.delHost("mysite.com"); // if you call it a second time, it segfaults O.o

非常感谢您提供帮助。

编辑:我将调用 erase() 返回的值分配给 viter,结果相同。我仍然不知道为什么会这样。

如果您需要所有代码,请访问http://paste.pocoo.org/show/363051/

【问题讨论】:

    标签: c++ vector segmentation-fault


    【解决方案1】:

    一般最好使用std::remove_if从一个向量中删除多个项目;它以线性时间而不是二次时间运行,并且不必担心迭代器失效。

    可能看起来像这样:

    hosts.erase(std::remove_if(hosts.begin(), 
                               hosts.end(), 
                               [&blockedhost](const HostEntry& entry) {
                                   return entry.getHost() == blockedhost || 
                                          entry.getHost() == "www." + blockedhost;
                               }),
                hosts.end());
    

    你可以在没有 C++0x lambda 的情况下通过一个结构来完成类似的事情来比较:

    struct RemoveBlockedHost {
        RemoveBlockedHost(const std::string& s): blockedHost(s) {}
        bool operator () (const HostEntry& entry) {
            return entry.getHost() == blockedHost || entry.getHost() == "www." + blockedHost;
        }
        const std::string& blockedHost;
    };
    
    hosts.erase(std::remove_if(hosts.begin(), hosts.end(), RemoveBlockedHost(blockedhost)), hosts.end());
    

    【讨论】:

    • 我只想删除两个项目 - 都包含某个主机,一个带有 www。前缀,一个没有。那会只删除包含 blockedhost 的主机条目吗?它似乎会从blockedhost的第一个索引删除到最后。
    • 假设我没有弄乱我的语法,它应该只删除你想要的项目。 remove_if 将所有匹配谓词的项目移动到末尾;然后它从返回的迭代器中擦除到向量的末尾。
    • 啊啊,好的。另外,或者paste.pocoo.org/show/363058 也是可接受的语法吗?不过,我可能会使用您的 Lambada 示例。
    • 我想这会奏效,尽管在没有您要删除的条目的情况下复制整个容器并不是最优雅的解决方案。
    【解决方案2】:

    您正在从您正在迭代的向量中删除项目!您想将viter 设置为从erase 返回的值。请参阅 C++ 文档以获取 vector::erase

    【讨论】:

    • 啊,谢谢。我完全忘记了修改您正在迭代的列表/向量是不好的。我会试试看,看看能不能解决。
    • 唉,没用。我有完全一样的问题。帖子上的代码现已更新。
    【解决方案3】:

    当你删除一个向量成员时,它会使迭代器失效。

    Std::lists 旨在允许您像这样在中间删除而不会使迭代器无效。因此,对于这个特定的操作,它将允许最简单的代码。

    但是,向量可能仍然会更好,整体 IF 性能是一个问题。只有当列表有足够多的成员并且您在中间删除足够多时,列表才会看到它允许的不太复杂的代码的性能优势。

    【讨论】:

    • 确实,我计划拥有 200 多个项目。我认为向量会起作用,但使用 viter = hosts.erase(viter) 仍然不起作用。
    【解决方案4】:

    在您修改viter 迭代的集合后,viter 不再有效。

    【讨论】:

      【解决方案5】:

      我没有从代码中看到任何错误。我认为你应该运行你的调试版本,并在 delHost() 处放置断点。逐步检查以找出导致 seg 故障问题的原因。

      【讨论】:

        猜你喜欢
        • 2010-10-27
        • 2010-12-04
        • 2014-10-24
        • 1970-01-01
        • 2010-11-26
        • 2011-05-25
        • 1970-01-01
        • 2011-09-08
        • 1970-01-01
        相关资源
        最近更新 更多