您好我对C ++中的内存管理有一般性查询。 在这个程序的帮助下,我只知道new用于在堆上分配内存,临时变量在堆栈上分配内存。如果我们在堆上分配内存,我们也必须手动释放它,否则会有内存泄漏
但是在程序中我通过在堆上创建一个类型为BST的新变量temp来更新名为Insert的函数中的BST结构对象。但是我不知道如何释放该内存。如果我使用free命令在函数的末尾,即free(temp),然后存储在该内存中的值将丢失,如果我再次尝试访问它,我将得到一个错误,我当然不能在main中使用free(temp),因为它不是一个局部变量到main。 有人可以告诉我应该做些什么。
顺便说一下,我必须提一下,如果不使用free(temp),我的程序也能正常运行但是我猜内存泄漏正在发生,这很糟糕。
我也有点困惑,为什么我的程序运行没有错误,如果我评论析构函数~BST()
但在我取消注释时给出链接器错误。
#include<iostream>
#include<string>
#include<conio.h>
#include<array>
#include<stack>
#include<sstream>
#include<algorithm>
#include<vector>
#include<ctype.h>//isdigit
#include<deque>
#include<queue>
#include<map>
using namespace::std;
struct BST
{
int data;
BST *left;
BST *right;
BST(int d,struct BST* l,BST *r):data(d) , left(l) ,right(r)
{
}
BST()
{
}
//~BST();
};
void levelOrder(struct BST *root)
{
struct BST *temp=NULL;
int count =0;
deque<struct BST*> dq;
if(!root)
{
return;
}
dq.push_back(root);
count=dq.size();
while(!dq.empty())
{
temp=dq.front();
cout<<temp->data<<" ";
if(temp->left)
{
dq.push_back(temp->left);
}
if(temp->right)
{
dq.push_back(temp->right);
}
dq.pop_front();
if(--count==0)
{
cout<<endl;
count=dq.size();
}
}
}
void Insert(struct BST*root,int data)
{
//struct BST temp(data,NULL,NULL);
BST *temp = new BST(data,NULL,NULL);
temp->data =data;
temp->left= NULL;
temp->right=NULL;
if(!root)
{
return;
}
while(root)
{
if((root)->data >data)
{
(root)=(root)->left;
if(!(root)->left)
{
(root)->left=temp;
break;
}
}
else
{
(root)=(root)->right;
if(!(root)->right)
{
(root)->right=temp;
break;
}
}
}
}
int main()
{
deque<struct BST> dq1,dq2;
BST e(4,NULL,NULL);
BST f(3,NULL,NULL);
BST d(1,&f,NULL);
BST b(2,&d,&e);
BST c(8,NULL,NULL);
BST a(6,&b,&c);
levelOrder(&a);
Insert(&a,5);
cout<<a.left->right->right->data;
cout<<endl;
levelOrder(&a);
_getch();
return 0;
}
答案 0 :(得分:1)
首先,在C ++中,您通常应该使用new
和delete
(它们称为ctors / dtors等)。对于数组,请使用delete[]
。 new
/ delete
与malloc
/ free
不兼容。
我猜BST是一个二叉搜索树。所以你有一个动态分配内存的树。
你必须释放整棵树,这意味着你也应该按顺序完成它,以免你得到悬空指针。
通过确保BST节点永远免费为其子节点,可以显着降低复杂性。然后,当您删除根节点时,它将递归删除所有其他节点。
在我看来,最简单的方法是使用智能指针,如shared_ptr<T>
,unique_ptr<T>
或auto_ptr
(最后一个有警告,但我不是要在这里解决它们。)
结构将如下所示:
struct BST
{
/* ctor, dtor omitted for brevity. */
std::unique_ptr<BST> left;
std::unique_ptr<BST> right;
}
您的BST节点超出范围,即您delete
,或者它在堆栈上分配,代码退出块。调用左侧和右侧的析构函数,unique_ptr
实现确保在它存储的指针上调用delete
。
答案 1 :(得分:0)
BST *temp
方法中创建的Insert
是您插入的新节点/子树,在整个树被破坏或节点之前,您不希望delete
它在您尚未编写的某种Delete
函数中删除。
关于你的最后一点:
在没有析构函数的情况下运行此特定程序将泄漏内存,但不会访问任何无效的内存段,这就是它运行没有任何错误的原因。
当您在代码中取消注释析构函数声明时,您会收到链接器错误,因为您没有定义析构函数,您刚刚告诉编译器/链接器那里应该是一个析构函数,但没有。即使你只想要一个空的,也必须是~BST() {}
。
答案 2 :(得分:0)
两个构造函数都应该为左右成员分配默认值,至少为NULL; 不应在课外指定值。将默认参数添加到构造函数中。为避免泄漏,您不应在需要之前创建对象。或者有一个标志,最初是假的,你设置为true如果你已经使用它。如果标志仍为假,则在返回时删除。
答案 3 :(得分:0)
首先,您应该使用new
和delete
在C ++中进行内存管理,而不是malloc()
和free()
。
如上所述,请注意您指定另一个指针left
或right
以指向最初分配给变量temp
的内存。您的树将允许您访问分配的内存,尽管通过除原始temp
变量之外的其他变量。这意味着您可以在delete
类中使用这些变量BST
内存。通常,这是在析构函数内完成的。
请注意,您在此处管理内存,而非变量。让我们看一下这个简单的例子:
int main() {
int* intPtr = new int;
int* temp = intPtr;
delete temp;
temp = NULL;
}
如您所见,此代码分配一个内存块来存储int
。这个内存有两个指针。只要不同时删除内存,就可以使用任一指针删除内存。当您了解内存管理时,这绝对是一种平衡行为。您必须确保释放所有内存,而不要尝试两次释放同一块内存。