我已经实现了一个简单的链接列表,但在删除我使用的所有指针后似乎没有释放内存。我希望有人能指出我在这里缺少的东西。我正在使用Activity Monitor来查看xcode的内存使用情况,也许这是一种查看内存使用情况的真空方法?我不确定。这是代码:
#include <iostream>
struct node {
int data;
node *next;
};
//function to traverse linked list
void traverse(node *root){
node *trav;
std::cout << "The list is as follows:\n";
//traverses through lists
trav = root;
do{
std::cout << (*trav).data << "\n";
trav = trav->next;
}while(trav != NULL);
std::cout << "\n";
delete trav;
}
void addToList(node *root){
node *tmp;
tmp = root;
if(tmp->next != NULL){
while(tmp->next !=0){
tmp = tmp->next;
}
}
//adds new nodes to list
for(int i = 0 ; i<1000000 ; i++){
tmp->next = new node;
tmp = tmp->next;
tmp->data = i;
}
tmp->next = NULL;
delete tmp;
}
int main(int argc, const char * argv[])
{
node *root; //this is the root node. it will not change
//sets up root node
root = new node; //root points to a node structure (this is a memory address)
root->next=NULL; //next pointer is now "0"
root->data = 5; //data in this node = 5
//print initial list
traverse(root);
//add to list
addToList(root);
//print new list
traverse(root);
delete root;
return 0;
}
===================编辑 - 美国东部时间上午9:28,1月27日================== ==============
谢谢大家的好评。我知道我做了很多错事(这是我对c ++和动态内存分配的介绍。我很感激帮助!)
请在下面找到更新的代码。我遇到了以下问题: 1 - 再次,活动监视器报告的实际内存使用量没有从运行此过程的进程中释放(从终端运行并且xcode都显示此信息)。发生以下故障时会发生这种情况,但是当我将addToList中的for循环设置为远低于65514 时,也会发生这种情况。 - &GT;固定 - 这不再是一个问题(缺少一对括号,导致我的代码无法正确删除。糟糕!)
2 - 在data = 65514的节点上,我得到:〜节点第一行的EXC_BAD_ACCESS(代码2) - 为什么? Xcode提供以下内容:
Exception State Registers
trapno unsigned int
err unsigned int
faultvaddr unsigned long
Floating Point Registers
fctrl unsigned short
fstat unsigned short
ftag unsigned char
fop unsigned short
fioff unsigned int
fiseg unsigned short
fooff unsigned int
foseg unsigned short
mxcsr unsigned int
mxcsrmask unsigned int
stmm0 <invalid>
stmm1 <invalid>
stmm2 <invalid>
stmm3 <invalid>
stmm4 <invalid>
stmm5 <invalid>
stmm6 <invalid>
stmm7 <invalid>
xmm0 <invalid>
xmm1 <invalid>
xmm2 <invalid>
xmm3 <invalid>
xmm4 <invalid>
xmm5 <invalid>
xmm6 <invalid>
xmm7 <invalid>
xmm8 <invalid>
xmm9 <invalid>
xmm10 <invalid>
xmm11 <invalid>
xmm12 <invalid>
xmm13 <invalid>
xmm14 <invalid>
xmm15 <invalid>
General Purpose Registers
rax unsigned long
rbx unsigned long 0x0000000000000000
rcx unsigned long
rdx unsigned long
rdi unsigned long
rsi unsigned long
rbp unsigned long 0x00007fff6ca0c210
rsp unsigned long 0x00007fff6ca0c1c0
r8 unsigned long
r9 unsigned long
r10 unsigned long
r11 unsigned long
r12 unsigned long 0x0000000000000000
r13 unsigned long 0x0000000000000000
r14 unsigned long 0x0000000000000000
r15 unsigned long 0x0000000000000000
rip unsigned long 0x000000010d60cb96
rflags unsigned long
cs unsigned long
fs unsigned long
gs unsigned long
我认为这与无符号短路的限制有关,如某些寄存器中所见,但是,我没有使用无符号短路。 ??!?!
这是我目前的代码:
#include <iostream>
struct node {
long data;
node *next;
node():next(NULL){} //just to be safe, initialize as null to start
//destructor used to clean up list nodes
~node(){
std::cout << data << " ";
if(next != NULL){
std::cout << data << ": deleted\n";
delete next;
next = NULL;
}
}
};
//function to traverse linked list
void traverse(node *root){
node *trav;
std::cout << "The list is as follows:\n";
//traverses through lists
trav = root;
do{
std::cout << (*trav).data << "\n";
trav = trav->next;
}while(trav != NULL);
std::cout << "\n";
}
void addToList(node *root){
node *tmp;
tmp = root;
if(tmp->next != NULL){
while(tmp->next !=0){
tmp = tmp->next;
}
}
//adds new nodes to list
for(long i = 0 ; i<100000 ; i++){
tmp->next = new node;
tmp = tmp->next;
tmp->data = i;
}
tmp->next = NULL;
}
int main(int argc, const char * argv[])
{
node *root; //this is the root node. it will not change
//sets up root node
root = new node; //root points to a node structure (this is a memory address)
root->next=NULL; //next pointer is now "0"
root->data = 5; //data in this node = 5
//print initial list
//traverse(root);
//add to list
addToList(root);
//print new list
//traverse(root);
delete root;
return 0;
}
答案 0 :(得分:0)
你没有删除你创建的所有节点,你必须遍历所有节点列表,从根节点开始,然后一个接一个地删除它们 (应考虑为此制作删除功能)
类似的东西:
node *actual, *next;
actual = root;
while (actual != null)
{
next = actual->next;
delete actual;
actual = next;
}
答案 1 :(得分:0)
问题是您删除了根节点,但这并不会自动删除直接和间接链接到它的所有节点。
如果您希望这样做,您可以为node
创建一个析构函数,delete
是next
指针所指向的对象,如果这不是NULL
。这将展开一系列析构函数调用,这些调用将最终删除链接到您正在删除的节点的所有节点。
或者您甚至可以向后手动遍历列表并根据需要delete
每个节点,但我不建议 - 它不必要地复杂且容易出错。
addToList()
中的另一个(无关,但同样糟糕,甚至更糟)问题。你不应该这样做:
delete tmp;
它将删除列表中上一个节点仍指向的对象。这会创建一个悬空指针(即一个非NULL指针,似乎指向某个现有对象,但实际上并非如此)。
类似的考虑适用于函数traverse()
,正如@ us2012正确指出的那样:
delete trav;
这条delete
指令不会创建任何悬空指针,但是没用,因为delete
运算符在输入指针为NULL
时无效(这是你的情况)。
答案 2 :(得分:0)
进行以下修改
struct node {
int data;
node *next;
node():next(NULL){} //just to be safe
~node(){if(next != NULL) delete next;}
};
问题是你只删除根而不删除其他元素。此更改将确保在删除节点时,它将删除下一个节点(如果存在)。
不是最传统的解决方案,而是以自己的方式优雅..(如果列表太长,可能会导致堆栈问题,ppetrov显示的while循环没有这个问题,或者它是尾递归?)
你还应该修复其他人提到的其他多余的delete
。
这个实现接近于一个名为Resource Acquisition Is Initialization的概念,这个概念可以帮助智能指针和库的其他部分工作。
答案 3 :(得分:0)
一般指南是,如果您的代码包含delete
,那么您几乎可以肯定这样做非常非常错误。
struct node {
int data;
std::unique_ptr<node> next;
};
现在每个node
会在链被破坏时销毁链中的下一个node
,这意味着列表会自行清理。您可以在堆栈上分配第一个node
,允许它在超出范围时被释放,或者使用另一个unique_ptr
。
您也绝对不想在遍历时删除列表。