【问题标题】:C++ - std::list.erase() not removing elementC++ - std::list.erase() 不删除元素
【发布时间】:2020-10-10 21:01:11
【问题描述】:

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

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

但是.. 使用stl::list 实现,我不知所措。这是我到目前为止所拥有的,其中 DOCO 是一个类,列表中的元素是指向类实例的指针。我研究了remove()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;
}

【问题讨论】:

  • 您能给我们提供一个minimal reproducible example 来重现该行为吗?乍一看,您的代码看起来还不错。
  • 当您尝试从列表中删除它时,不要在顶部条件块中声明本地“删除 * 它”,它显然不存在。请参阅en.cppreference.com/w/cpp/container/list/erase 中的示例
  • 您要擦除的列表是原始列表的副本,因为该函数是通过值传递调用的。
  • 啊等等,我要快。您正在处理列表的副本。您必须通过引用传递它:bool DOCO::kill_doco(std::list &lt; DOCO* &gt;&amp; docolist, int docoid)
  • “一项学校作业(我知道这里不应该这样做” - 不让别人帮你做作业,但会问一个从你的作业中产生的具体问题很好。

标签: c++ list std


【解决方案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 没有被函数修改。留在原始列表中的“悬空”指针是第二个咬你的东西。

【讨论】:

  • 哦!绝对是这样。直到最近我才做很多 C++,这也可以解释为什么我错过了它(主要是在做汇编工作)。你和@krisz 是救生员。现在我的清单崩溃了,但我有一种感觉,我知道为什么给出你的解释。谢谢!!
  • @TheN00bBuilder,如果您使用了std::unique_pointer,而不是带有new/delete 的原始指针,编译器会在这里为您提供帮助。尝试使用std::shared_ptrstd::unique_ptr 或其他容器类而不是new/delete。实际上,在现代 c++ 中,除了实现智能指针外,您不需要使用new/delete。你会惊讶于你的代码会变得多么简单和更少错误。
猜你喜欢
  • 1970-01-01
  • 2018-06-14
  • 1970-01-01
  • 1970-01-01
  • 2011-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-18
相关资源
最近更新 更多