2009-12-10 15 views
9

それはこのような関数の引数として渡されたポインタを削除しても大丈夫(および法的)です:これは今も元気にコンパイル関数の引数として渡されたポインタに削除使用

#include<iostream> 

class test_class{ 
public: 
    test_class():h(9){} 
    int h; 
    ~test_class(){std::cout<<"deleted";} 
}; 

void delete_test(test_class* pointer_2){ 
    delete pointer_2; 
} 

int main(){ 
    test_class* pointer_1; 

    while(true){ 
     pointer_1 = new test_class; 

     //std::cout<<pointer_1->h; 

     delete_test(pointer_1); 
    } 
} 

を、私はちょうどほしいですそれが常にそのようになることを確認してください。

答えて

11

エラーなくコンパイルされます。

ポインタを関数に渡してその関数で削除することは、プログラムの仕様によっては、別の話である可能性があります。

あなたが考慮する必要がある主なアイデアは、指差しデータの「所有権」です。そのポインタを渡すと、渡されているデータの所有権を呼び出し関数が持っていますか?すなわち、このデータを参照できる唯一の場所にありますか?呼び出し元の関数がデータを再び参照することはありませんが、指し示されたデータの所有権を放棄していますか?その場合は、削除する必要があります。

呼び出し側の関数がデータを再度参照する可能性がある場合は、削除しないでください。

さまざまなデータ構造を介してデータへの他の参照がある場合は、その場所からデータを再度参照しないようにコード内に規律がない限り、このデータを削除することは安全ではありません。これはやりにくく、多くのプログラミングバグの原因です。

C++ tr1のshared_ptr < >は、このような状況に役立つスマートポインタです。データへの参照数を追跡する参照カウントを保持することによって、この所有権の概念を管理します。参照カウントが1の場合、1つの明確な所有者が存在する。参照カウントが1より大きい場合、所有権は共有されます。参照カウントが0の場合、データへの参照はなくなり、shared_ptr < >デストラクタが呼び出されると、shared_ptr < >はそれを削除します。

+0

私がいつも驚いたことは、ポインタが 'const'であってもそれを削除することが合法だということです。 –

2

はい、これは完全に合法です。 deleteは、ヒープ上に割り当てられたオブジェクト(または0に等しい)を指している限り、どこからでもポインタを取得できます。

呼び出し元が関数によってオブジェクトを削除することを期待するかどうかは、別の質問です。

7

はい、これは有効です。

これは一般的にCで行われます(mallocとnewとdeleteの代わりにfree、明らかに)。 C++では、可能であれば、RAIIのような他のメモリ管理イディオムを使用することが一般に好ましい。

6

はい、C++では合法ですが、これを行うのは一般的には良い方法ではありません。 newdeleteのクラスは常に同じです。

+0

私は与えられたコードのどこにでも "新しい"を実行するクラスはありません。あなたはたぶん "クラス"の代わりに "ブロック"を意味するかもしれませんが、それはいつも可能であるとは限りません。 –

+0

しかし、そのクラスは、パラメータとしてポインタをとる関数を使って削除を実行することができます。 –

0

これは完全に合法です。そのポイントの後にポインタが呼び出し元で使用されていないことを確認する必要があります。一般に、削除を行っている関数の名前は、何が起こっているのかを示すべきである(例えば、削除、解放、フリーなどを含む)。もう1つの潜在的な問題は、指し示されたデータが新規ではなく新しい[]で割り当てられていることを確認することです。

1

これは完全に正当ですが、そのような場合はおそらくメモリの所有権をboost::shared_ptrのように管理するほうがよいでしょう。

0

オブジェクトのクリーンアップメソッドを記述するときに有効です。ただし、クリーンアップロジックをデストラクタに入れたい場合は9/10倍ですが、非常に便利です。

別のクリーンアップを書いてもよい理由の1つは、オブジェクトを「生きている」ままにしておきたいのですが、しばらく使用しないでください。コンストラクタオーバーヘッドを必要としません。

ポインタを渡す場合は、定義されていない動作を避けるためにnullでないことを確認する必要があります。

関連する問題