C++ - std::list.erase() 不删除元素
C++ - std::list.erase() not removing element
我在学校作业中遇到了一些代码的小问题(我知道这里被回避了,但我把自己锁定在使用 std::list
库并为此付费)。我有一个函数,其中包含一个指向 classes 的指针列表以及属于我想要销毁并调整列表大小的那些 classes 之一的特定 ID。但是,使用我的代码,列表永远不会调整大小并且值是垃圾,这使我的程序崩溃。所以看起来实际的 class 被删除了,但该元素从未从列表中删除...
如果我有时间实现自己的双向链表,我会遍历列表以查找要删除的元素。如果找到,创建一个临时节点指针并将其指向我将要删除的节点。将前一个节点的“下一个”元素设置为迭代器的“下一个”元素,然后删除迭代器节点。
但是.. 使用 stl::list
实现,我不知所措。到目前为止,这是我所拥有的,其中 DOCO 是 class,列表中的元素是指向 classes 实例的指针。我研究了 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;
}
kill_doco(std::list < DOCO* > docolist
这会创建列表的 副本。此副本是指针列表。
您继续修改列表的副本,并删除其中的一个元素。
原始列表(您复制的)仍然具有原始指针,现在指向已删除的对象。
简单的解决方法是:
kill_doco(std::list < DOCO* >& docolist
C++ 是一种 value-oriented 语言,不同于 Java 或 C# 等语言。某事物的名称指的是该事物的实际值,而不是对它的引用。
指针同样是对象地址的值。
像语义一样的引用,或者pointer-like语义,可以在C++中完成。但是,与 Java/C# 不同的是,默认情况下,C++ 中的每个对象都是一个实际值。
从一种语言转向另一种语言(无论哪种方式)的人可能会对此感到困惑。
C++ 程序中的“默认”对象类型是常规类型——当您将其复制或类似操作时,该类型的行为类似于整数。离开这个相对容易,但这是默认设置。
所以你所做的类似于:
void clear_bit( int x, int bit ) {
x = x & ~(1 << bit);
}
令您惊讶的是您传入的值 x
并未被该函数修改。留在原始列表中的“悬垂”指针是第二个咬你的东西。
我在学校作业中遇到了一些代码的小问题(我知道这里被回避了,但我把自己锁定在使用 std::list
库并为此付费)。我有一个函数,其中包含一个指向 classes 的指针列表以及属于我想要销毁并调整列表大小的那些 classes 之一的特定 ID。但是,使用我的代码,列表永远不会调整大小并且值是垃圾,这使我的程序崩溃。所以看起来实际的 class 被删除了,但该元素从未从列表中删除...
如果我有时间实现自己的双向链表,我会遍历列表以查找要删除的元素。如果找到,创建一个临时节点指针并将其指向我将要删除的节点。将前一个节点的“下一个”元素设置为迭代器的“下一个”元素,然后删除迭代器节点。
但是.. 使用 stl::list
实现,我不知所措。到目前为止,这是我所拥有的,其中 DOCO 是 class,列表中的元素是指向 classes 实例的指针。我研究了 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;
}
kill_doco(std::list < DOCO* > docolist
这会创建列表的 副本。此副本是指针列表。
您继续修改列表的副本,并删除其中的一个元素。
原始列表(您复制的)仍然具有原始指针,现在指向已删除的对象。
简单的解决方法是:
kill_doco(std::list < DOCO* >& docolist
C++ 是一种 value-oriented 语言,不同于 Java 或 C# 等语言。某事物的名称指的是该事物的实际值,而不是对它的引用。
指针同样是对象地址的值。
像语义一样的引用,或者pointer-like语义,可以在C++中完成。但是,与 Java/C# 不同的是,默认情况下,C++ 中的每个对象都是一个实际值。
从一种语言转向另一种语言(无论哪种方式)的人可能会对此感到困惑。
C++ 程序中的“默认”对象类型是常规类型——当您将其复制或类似操作时,该类型的行为类似于整数。离开这个相对容易,但这是默认设置。
所以你所做的类似于:
void clear_bit( int x, int bit ) {
x = x & ~(1 << bit);
}
令您惊讶的是您传入的值 x
并未被该函数修改。留在原始列表中的“悬垂”指针是第二个咬你的东西。