查询与C ++中的内存管理有关

时间:2013-03-02 22:55:12

标签: c++ pointers free new-operator destructor

您好我对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;
}

4 个答案:

答案 0 :(得分:1)

首先,在C ++中,您通常应该使用newdelete(它们称为ctors / dtors等)。对于数组,请使用delete[]new / deletemalloc / 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)

首先,您应该使用newdelete在C ++中进行内存管理,而不是malloc()free()

如上所述,请注意您指定另一个指针leftright以指向最初分配给变量temp的内存。您的树将允许您访问分配的内存,尽管通过除原始temp变量之外的其他变量。这意味着您可以在delete类中使用这些变量BST内存。通常,这是在析构函数内完成的。

请注意,您在此处管理内存,而非变量。让我们看一下这个简单的例子:

int main() {
    int* intPtr = new int;
    int* temp = intPtr;

    delete temp;
    temp = NULL;
}

如您所见,此代码分配一个内存块来存储int。这个内存有两个指针。只要不同时删除内存,就可以使用任一指针删除内存。当您了解内存管理时,这绝对是一种平衡行为。您必须确保释放所有内存,而不要尝试两次释放同一块内存。