C++ - std::list.erase() 不删除元素

C++ - std::list.erase() not removing element

提问人:TheN00bBuilder 提问时间:10/11/2020 最后编辑:JaMiTTheN00bBuilder 更新时间:10/11/2020 访问量:594

问:

我在学校作业的一些代码上遇到了一个小问题(我知道这里被回避了,但我把自己锁在了使用图书馆上,并为此付费)。我有一个函数,它有一个指向传递给它的类的指针列表,以及一个属于我想要销毁和调整列表大小的类之一的特定 ID。但是,使用我的代码,列表永远不会调整大小,并且值是垃圾,这会使我的程序崩溃。因此,看起来实际的类正在被删除,但该元素从未从列表中删除......std::list

如果我有时间制作自己的双向链表实现,我会遍历列表,寻找要删除的元素。如果找到它,请创建一个临时节点指针,并将其指向我将要删除的节点。将上一个节点的“next”元素设置为迭代器的“next”元素,然后删除迭代器节点。

但。。使用实现,我不知所措。这是我到目前为止所拥有的,其中 DOCO 是一个类,列表中的元素是指向类实例的指针。我已经研究了 vs. ,也许两者都使用可能会解决它,但我不确定如何使用这样的迭代器实现。stl::listremove()erase()remove()

bool DOCO::kill_doco(std::list < DOCO* > docolist, int docoid)
{
    for (std::list<DOCO*>::iterator it = docolist.begin(); it != docolist.end(); )
    {
        if ((*it)->id == docoid)
        {
            delete * it;
            it = docolist.erase(it);
            std::cerr << "item erased\n";
        }
        else
        {
            ++it;
        }
    }
    std::cerr << "leaving kill\n";
    
    return true;
}
C++ 列表 std

评论

1赞 πάντα ῥεῖ 10/11/2020
您能否为我们提供一个最小的可重现示例来重现该行为?乍一看,您的代码看起来还不错。
0赞 Ian4264 10/11/2020
不要在顶部条件块中声明本地“delete * it”,因为您尝试将其从列表中删除,它显然不存在。请参阅 en.cppreference.com/w/cpp/container/list/erase 中的示例
0赞 Wander3r 10/11/2020
要擦除的列表是原始列表的副本,因为该函数是使用按值传递调用的。
0赞 πάντα ῥεῖ 10/11/2020
啊,等等,我快点。您正在处理列表的副本。您必须通过引用来传递它:bool DOCO::kill_doco(std::list < DOCO* >& docolist, int docoid)
3赞 JaMiT 10/11/2020
“学校作业(我知道这里是回避的”——要求别人做你的作业是回避的,但问一个你家庭作业中出现的特定问题是可以的。

答:

3赞 Yakk - Adam Nevraumont 10/11/2020 #1
kill_doco(std::list < DOCO* > docolist

这将创建列表的副本。此副本是指针列表。

继续修改列表的副本,并删除其中的元素。

原始列表(您复制的)仍具有原始指针,该指针现在指向已删除的对象。

简单的解决方法是:

kill_doco(std::list < DOCO* >& docolist

C++是一种面向价值的语言,与Java或C#等语言不同。某物的名称是指该事物的实际值,而不是对它的引用。

指针同样是对象地址的值。

类似语义的引用,或类似指针的语义,可以在C++中完成。但是,与 Java/C# 不同的是,默认情况下,C++ 中的每个对象都是一个实际值。

从一种语言转移到另一种语言(无论哪种方式)的人都会对此感到困惑。

C++ 程序中的“默认”对象类型是常规类型——当你复制它时,它就像一个整数,等等。摆脱这一点相对容易,但这是默认设置。

所以你所做的类似于:

void clear_bit( int x, int bit ) {
  x = x & ~(1 << bit);
}

并且惊讶于您传入的值没有被函数修改。原始列表中留下的“悬空”指针是咬你的第二件事。x

评论

0赞 TheN00bBuilder 10/11/2020
哦!确实是这样。直到最近我才做太多C++,这也可以解释为什么我错过了它(主要是在做汇编工作)。你和@krisz都是救命恩人。现在我的清单崩溃了,但我有一种感觉,我知道为什么,因为你的解释。谢谢!!
0赞 HAL9000 10/11/2020
@TheN00bBuilder,如果您使用 ,而不是带有 / 的原始指针,编译器会在这里为您提供帮助。尝试使用 ,或其他容器类,而不是 /。实际上,在现代 c++ 中,您根本不需要使用 /,除非实现智能指针。你会惊讶于你的代码会变得多么简单和更少。std::unique_pointernewdeletestd::shared_ptrstd::unique_ptrnewdeletenewdelete