1

C++クラスと動的配列の知識を組み合わせ始めたところです。「新しい演算子を使うときはいつでも」削除すべきだというアドバイスを受けました。デストラクタがどのように機能するかも知っているので、このコードは正しいと思います。

main.cpp

...
int main()
{
    PicLib *lib = new PicLib;
    beginStorage(lib);
    return 0;
}

void beginStorage(PicLib *lib)
{
...
    if (command != 'q')
    {
        //let's assume I add a whole bunch
            //of stuff to PicLib and have some fun here
        beginStorage(lib);
    }
    else
    {
        delete lib;
        lib = NULL;
        cout << "Ciao" << endl;
    }
}

PicLib.cpp

...

PicLib::PicLib()
{
    database = new Pic[MAX_DATABASE];
    num_pics = 0;
}

PicLib::~PicLib()
{
    delete[] database;
    database = NULL;
    num_pics = 0;
}
...

PicLibに、Picより動的な配列を含むクラスを入力します。Picのデストラクタは、上記と同じ方法でそれらを削除します。私はそれdelete [] databaseがそれらすべてのクラスを適切に取り除くと思います。

では、 main.cppでの削除は必要ですか?ここでハンキーなドーリーに見えるものはすべてありますか?

4

8 に答える 8

5

いくつかの問題があります。

int main() 
{ 
  PicLib *lib = new PicLib; 
  beginStorage(lib); 
  return 0; 
}

見つけやすいように、同じスコープでメモリの割り当てと削除を行うことをお勧めします。

ただし、この場合はローカルで宣言するだけです (参照渡し):

int main() 
{ 
    PicLib  lib; 
    beginStorage(lib); 
    return 0; 
}

beginStorage() で

しかし、ポインターを操作する理由はわかりません。参照渡しして、ローカルで使用してください。

void beginStorage(PicLib& lib)
{
 ....
}

PicLib クラスには RAW ポインタがあります: データベースです。

RAW ポインターを所有している (作成して破棄する) 場合は、コピー コンストラクターと代入演算子のコンパイラ生成バージョンをオーバーライドする必要があります。しかし、この場合、ポインターを使用する理由はわかりません。ベクトルを使用する方が簡単です。

class PivLib
{
    private:
        std::vector<Pic>   databases;
};
于 2010-03-03T17:04:50.697 に答える
3

はい、new で作成したものはすべて deleteで削除する必要があり、 new[]で作成したものはすべてdelete[]で削除する必要があります。

ただし、コードで指摘したいことがいくつかあります。

  • new[] と delete[] を使用するよりも std::vector<> を優先します。それはあなたのためにメモリ管理を行います。auto_ptr、shared_ptr、C++0x の unique_ptr などの自動メモリ管理用のスマート ポインターも参照してください。これらは、削除を忘れてメモリ リークを引き起こすのを防ぐのに役立ちます。可能であれば、new/new[]/delete/delete[] をまったく使用しないでください。
  • 何かを新規作成して削除する必要がある場合は、クラス コンストラクターで新規作成し、クラス デストラクタで削除することをお勧めします。例外がスローされたり、オブジェクトがスコープ外になったりすると、それらのデストラクタが自動的に呼び出されるため、メモリ リークを防ぐことができます。RAIといいます。
  • beginStorageにそのパラメーターを削除させることは、潜在的に悪い考えです。ポインターを削除できないため、 newで作成されていないポインターで関数を呼び出すと、クラッシュする可能性があります。new と delete を使用するのではなく、main()がスタック上に PicLib を作成し、beginStorage が参照を取り、何も削除しない方がよいでしょう。
于 2010-03-03T17:02:03.043 に答える
2

はい、auto_ptrを使用しない限り、必要です(auto_ptrを使用する前に、auto_ptrのセマンティクスを確認してください。コピーすることはできません)。

例えば ​​:

int main()
{
    auto_ptr<PicLib> lib = new PicLib;
    beginStorage(lib);
    return 0;
} // auto_ptr goes out of scope and cleans up for you
于 2010-03-03T16:57:40.787 に答える
2

elseとは行きませんwhile。あなたはもっと次のようなものが欲しいでしょう:

void beginStorage(PicLib *lib)  
{  
    while (command != 'q') 
    { 
        //let's assume I add a whole bunch 
            //of stuff to PicLib and have some fun here 
    } 

    delete lib; 
    lib = NULL;  // Setting to NULL is not necessary in this case,
                 // you're changing a local variable that is about
                 // to go out of scope.
    cout << "Ciao" << endl;
}

delete見た目は良さそうですが、PicLibオブジェクトの所有権を取得するドキュメントを作成する必要がありbeginStorageます。そうすれば、を使用している人は誰でもbeginStorage、後でそれを削除する必要がないことを知っています。

于 2010-03-03T16:58:55.927 に答える
2

main.cpp の削除が必要です。

これはおそらく個人的な好みの問題ですが、new と delete を別々の論理部分で呼び出さないことをお勧めします (ここでは、PicLib インスタンスの delete 呼び出しは別の関数にあります)。通常、割り当てと解放の責任は 1 つの部分だけに与えた方がよいでしょう。

@AshleysBrain には、(PicLib スタックの作成に関する) より良い提案がありますが、PicLib がメモリを消費しすぎると問題が発生する可能性があります。

于 2010-03-03T17:04:55.507 に答える
1

通常、新しい場所と同じ場所で削除します。お会計が楽になります。スマート ポインター (この場合は scoped_ptr) を使用することをお勧めします。これは、while の本体が例外をスローして途中で終了した場合でも、コードが正しいことを意味します。

于 2010-03-03T17:04:33.063 に答える
0

すべてがよさそうだ。

main.cppでの削除が必要なのは、deleteを呼び出さなかった場合、デストラクタが実行されず、配列が削除されないためです。また、配列だけでなく、クラスのメモリもリークすることになります。

于 2010-03-03T16:58:52.343 に答える
0

はい、それ以外の場合、PicLib のデストラクタは呼び出されません。

ただし、文体上の注意点が 1 つあります。関数内でメソッド スコープ オブジェクトを新規作成する場合は、同じ関数内でそれを削除してみてください。他の人のメモリリークを修正する大規模なプロジェクトを経験しなければならなかったジュニアエンジニアとして...これにより、他の人が物事を読みやすくなります。見た目から、beginStorage() が戻った後に *lib を削除できます。そうすれば、*lib のスコープを 1 か所で確認しやすくなります。

于 2010-03-03T17:06:21.400 に答える