假设我有一个由类
定义的双向链表 class list
{
/*...*/
private:
struct node
{
node* prev;
node* next;
int* value;
}
node* first; //NULL if none
node* last; //NULL if none
/*...*/
}
如果我想为此列表创建析构函数,我是否必须明确删除该值?
list::~list()
{
node* move = first;
while(first)
{
first = move->next;
delete move;
move = first;
}
}
上述工作是否可以确保没有内存泄露?或者我必须这样做:
list::~list()
{
node* move = first;
while(first)
{
first = move->next;
delete move->value;
delete move->prev;
delete move;
move = first;
}
}
我很困惑如何在这种情况下确保没有内存泄露。我如何具体处理节点中的指针?如果我删除move会自动处理这些吗?
答案 0 :(得分:1)
您需要将每个new
与一个delete
配对。也就是说,您可能不希望delete prev
(此节点已被删除),但您想要delete value
。好吧,我将value
嵌入到对象中,而不是指向它:
struct node
{
node* prev;
node* next;
int value;
};
如果value
绝对需要成为指针,我会使用std::unique_ptr<int>
(或者,如果您需要使用C ++ 2003,则为std::auto_ptr<int>
)。
答案 1 :(得分:1)
对于每个成功的new
表达式,请在该对象上为delete
完全> 。
对于每个成功的new[]
表达式,请在该对象上为delete[]
完全> 。
这意味着你的清理功能都没有问题:
第一个功能会忘记delete
value
,这意味着内存泄漏。
通过删除列表中每个节点的move
和move->prev
,第二个功能可能会删除大多数节点两次,即未定义行为。 / p>
为避免第一个函数的内存泄漏,只需直接存储整数,而不是动态分配它。
答案 2 :(得分:1)
是否必须通过value
成员删除内存指针 - 只有您可以知道。这是一个关于内存所有权的问题,一个关于你的设计的问题。如果列表拥有 value
成员指向的数据内存,那么您必须在列表析构函数中删除它(即当列表终止时,它拥有的数据随之消失)。
如果列表不拥有value
内存,那么您不应该删除它。同样,只有你可以回答你的列表是否应该拥有value
内存的问题。这是你的意图。
现在,对于node
对象占用的内存,它显然属于列表,因此必须在析构函数中小心地释放它。您的destcructor的第一个版本接近正确(第二个版本根本没有意义),除了它以略微混淆的方式编写。这应该足够了
list::~list()
{
while (first)
{
node *move = first;
first = first->next;
delete move;
}
}
(同样,如果您必须删除value
,则应在delete move->value
之前将delete move
添加到您的周期中。)
P.S。一旦得到这个,您可能想要查看各种智能指针类,它们允许您明确表达内存所有权关系,从而使编译器知道它们。如果使用得当,它们将使内存管理几乎自动化。