2

こんにちは、C++ でのメモリ管理に関する一般的な質問があります。このプログラムの助けを借りて、ヒープにメモリを割り当てるために new が使用され、スタックに一時変数が割り当てられていることを理解しました。また、ヒープにメモリを割り当てている場合は、手動で解放する必要があることもわかりました。そうしないと、メモリリークが発生します.

しかし、プログラムでは、ヒープにBST型の新しい変数tempを作成することにより、Insertという名前の関数でBST構造体のオブジェクトを更新しています.しかし、そのメモリを解放する方法がわかりません.最後にfreeコマンドを使用する場合関数、つまり free(temp) の場合、そのメモリに格納されている値が失われ、再度アクセスしようとするとエラーが発生します。また、ローカル変数ではないため、メインで free(temp) を使用することはできません。メインに。誰かが何をすべきか教えてもらえますか。

ところで、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

4 に答える 4

1

まず、C++ では一般的にnewandを使用する必要がありますdelete(ctors/dtors などを呼び出します)。配列の場合は、delete[]. new/は/deleteと互換性がありません。mallocfree

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か、スタックに割り当てられてコードがブロックを終了します。left と right のデストラクタが呼び出され、unique_ptr実装によってdelete格納されているポインタが確実に呼び出されます。

于 2013-03-02T23:06:59.990 に答える
0

まず、C++ でのメモリ管理には and ではなくandnewを使用する必要があります。deletemalloc()free()

そうは言っても、最初に変数に割り当てられたメモリを指すleftか、別のポインタを割り当てることに注意してください。元の変数以外の変数を介しても、ツリーから割り当てられたメモリにアクセスできます。これは、クラスでこれらの変数を使用して記憶できることを意味します。通常、これはデストラクタ内で行われます。righttemptempdeleteBST

ここでは変数ではなくメモリを管理していることに注意してください。簡単な例で違いを見てみましょう。

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

    delete temp;
    temp = NULL;
}

ご覧のとおり、このコードは単一のメモリ ブロックを割り当てて、int. このメモリには 2 つのポインタがあります。両方で削除しない限り、どちらのポインタでもメモリを削除できます。メモリ管理について学ぶとき、これは間違いなくバランスをとる行為です。同じメモリ ブロックを 2 回割り当て解除しようとしないで、すべてのメモリが割り当て解除されていることを確認する必要があります。

于 2013-03-02T23:09:17.597 に答える
0

BST *tempメソッドで作成されたのはInsert、挿入する新しいノード/サブツリーです。deleteツリー全体が破棄されるか、まだ記述していない何らかのDelete関数でノードが削除されるまで、挿入したくありません。

最後のポイントについて:

デストラクタなしでこの特定のプログラムを実行すると、メモリ リークが発生しますが、無効なメモリ セグメントにはアクセスしないため、エラーなしで実行されます。

コード内のデストラクタ宣言のコメントを外すと、デストラクタを定義していないため、リンカ エラーが発生します。デストラクタが存在する必要があることをコンパイラ/リンカーに伝えただけですが、存在しません。空のものが必要な場合でも、~BST() {}.

于 2013-03-02T22:59:22.520 に答える
0

どちらのコンストラクターも、左右のメンバーに既定値 (少なくとも NULL) を割り当てる必要があります。クラス外で値を割り当てるべきではありません。コンストラクターにデフォルトのパラメーターを追加します。漏れを避けるために、必要になるまでオブジェクトを作成しないでください。または、最初は false のフラグを使用して、使用した場合は true に設定します。フラグがまだ false の場合は、戻り時に削除します。

于 2013-03-02T23:08:52.050 に答える