2

ポインター オブジェクトが 1 つのポイントに割り当てられており、それがさまざまな入れ子関数に返されているとします。ある時点で、このポインターが有効であるか、誰かによって既に割り当て解除されているかを確認した後、このポインターの割り当てを解除したいと考えています。

これらのいずれかが機能するという保証はありますか?

if(ptr != NULL)
   delete ptr;

また

if(ptr)
   delete ptr;

このコードは機能しません。それは常にセグメンテーション違反を与えます

#include <iostream>
class A
{
    public:
    int x;
     A(int a){ x=a;}
     ~A()
     { 
          if(this || this != NULL) 
              delete this;
     }
};
int main()
{ 
    A *a = new A(3);
    delete a;
    a=NULL;
}

編集

ポインターについて話すときはいつでも、人々はスマート ポインターを使用しない理由を尋ね始めます。スマートポインターがあるからといって、誰もが使えるわけではありません。

古いスタイルのポインターを使用するシステムに取り組んでいる可能性があります。ある晴れた日、それらすべてをスマートポインターに変換することはできません。

4

5 に答える 5

6

if(ptr != NULL) delete ptr;

また

if(ptr) delete ptr;

この 2 つは実際には同等であり、 と同じです。これは、ポインターのdelete ptr;呼び出しが機能することが保証されているためです (つまり、何もしません)。deleteNULL

ptrまた、 がダングリング ポインターである場合、動作することは保証されません。

意味:

int* x = new int;
int* ptr = x;
//ptr and x point to the same location
delete x;
//x is deleted, but ptr still points to the same location
x = NULL;
//even if x is set to NULL, ptr is not changed
if (ptr)  //this is true
   delete ptr;   //this invokes undefined behavior

delete this特定のコードでは、デストラクタを呼び出すと、デストラクタが再度呼び出されるため、例外が発生します。thisis neverであるためNULL、デストラクタが制御不能に再帰的になるため、STACK OVERFLOW が発生します。

于 2012-06-22T09:47:13.153 に答える
4

delete thisデストラクタを呼び出さないでください。

5.3.5、削除:削除式のオペランドの値がヌル ポインター値でない場合、削除式は、削除されるオブジェクトまたは配列の要素のデストラクタ (存在する場合) を呼び出します。

したがって、デストラクタ内で無限再帰が発生します。

それで:

if (p)
    delete p;

pnull でないかどうかのチェック( if (x)C++ ではif x != 0) は不要です。deleteすでにチェックしていますか。

これは有効です:

class Foo {
public:
    Foo () : p(0) {}
    ~Foo() { delete p; }
private:
    int *p;

    // Handcrafting copy assignment for classes that store 
    // pointers is seriously non-trivial, so forbid copying:
    Foo (Foo const&) = delete;
    Foo& operator= (Foo const &) = delete;
};

や何かへのポインタなどの組み込み型が自動的に初期化されると想定しないでください。したがって、それらをint明示的に初期化しない場合は、それらが自動的に初期化されると想定しないでください (グローバル変数のみがゼロで初期化されます)。float0

8.5 イニシャライザ:オブジェクトにイニシャライザが指定されていない場合、オブジェクトはデフォルトで初期化されます。初期化が実行されない場合、自動または動的ストレージ期間を持つオブジェクトの値は不定になります。[ 注: 静的またはスレッド ストレージ期間を持つオブジェクトは、ゼロで初期化されます。

だから:常に組み込み型を初期化してください!


私の質問は、ポインターの二重削除を回避し、クラッシュを防ぐ方法です。

デストラクタは、一度だけ出入りする必要があります。ゼロ回でも、2回でも、1回でもありません。

また、ポインターに到達できる場所が複数あるが、いつ削除できるかがわからない場合、つまり簿記をしている場合は、より単純なアルゴリズム、より単純なルール、または or のようなスマートポインターを使用しstd::shared_ptrますstd::unique_ptr

class Foo {
public:
    Foo (std::shared_ptr<int> tehInt) : tehInt_(tehInt) {}
private:
    std::shared_ptr<int> tehInt_;
};

int main() {
    std::shared_ptr<int> tehInt;
    Foo foo (tehInt);
}
于 2012-06-22T09:50:51.737 に答える
2

誰かが削除した後、ポインターが NULL に設定されるとは想定できません。これは、embarcadero C++ Builder XE の場合に当てはまります。後で NULL に設定される可能性がありますが、コードがそれを再度削除できないという事実を利用しないでください。

于 2012-06-22T09:48:40.303 に答える
0

「ある時点で、このポインターが有効かどうか、または誰かによって既に割り当てが解除されているかどうかを確認した後、このポインターの割り当てを解除したいと思います。」

C/C++ には、>naked pointer< が有効かどうかを確認する移植可能な方法がありません。それでおしまい。話はここまで。あなたはそれをすることはできません。繰り返しますが、ネイキッドまたは C スタイルのポインターを使用する場合のみ。その問題を抱えていない他の種類のポインタがあるので、代わりにそれらを使用しないでください!

さて、問題は次のようになります。なぜネイキッド ポインターを使用する必要があると主張するのでしょうか。ネイキッド ポインターを使用しないでください。andstd::shared_ptrstd::weak_ptr適切に使用してください。何も削除することを心配する必要さえありません。最後のポインターが範囲外になると、自動的に削除されます。以下は例です。

コード例は、ヒープに 2 つのオブジェクト インスタンス (整数とホルダー) が割り当てられていることを示しています。test() が戻ると、返さstd::auto_ptr<Holder>れた は caller によって使用されませんmain()。したがって、ポインターは破棄され、Holder クラスのインスタンスが削除されます。インスタンスが破棄されると、整数のインスタンスへのポインター (その整数を指す 2 つのポインターの 2 番目) が破棄されます。次にmyInt、同様に破棄されるため、整数への最後のポインタが破棄され、メモリが解放されます。心配することなく、自動的に。

class Holder {
  std::auto_ptr<int> data;
public:
  Holder(const std::auto_ptr<int> & d) : data(d) {}
}

std::auto_ptr<Holder> test() {
  std::auto_ptr<int> myInt = new int;
  std::auto_ptr<Holder> myHolder = new Holder(myInt);
  return myHolder;
}

int main(int, char**) {
  test(); // notice we don't do any deallocations!
}

C++ でネイキッド ポインターを使用しないでください。正当な理由はありません。自分の足を撃つことしかできません。複数回。放棄して;)

スマート ポインターの大まかなガイドラインは次のとおりです。

  • std::auto_ptr -- スコープがオブジェクトの唯一の所有者であり、オブジェクトの有効期間がスコープの終了時に終了する場合に使用します。したがって、auto_ptrがクラス メンバーである場合、クラスのインスタンスが破棄されると、ポイント先のオブジェクトが削除されることは理にかなっている必要があります。関数内で自動変数として使用する場合も同様です。それ以外の場合は、使用しないでください。

  • std::shared_ptr -- その使用は所有権を意味し、複数のポインター間で共有される可能性があります。ポイント先のオブジェクトの存続期間は、それへの最後のポインターが破棄されると終了します。オブジェクトの有効期間の管理は非常に簡単ですが、循環参照に注意してください。Class1 が Class2 のインスタンスを所有し、Class2 のまったく同じインスタンスが Class1 の以前のインスタンスを所有している場合、ポインター自体がクラスを削除することはありません。

  • std::weak_ptr -- その使用は非所有権を意味します。直接使用することはできませんが、使用する前に に戻す必要がありshared_ptrます。はオブジェクトのweak_ptr破棄を妨げないため、循環参照の問題は発生しません。それ以外の場合は、ぶら下がっていると使用できないという点で安全です。null ポインターをアサートまたは提示し、すぐにセグメンテーション違反を引き起こします。ダングリング ポインターの使用は、動作しているように見えることが多いため、さらに悪い方法です。

    実際、これが の主な利点ですweak_ptr。ネイキッド C スタイルのポインターを使用すると、誰かがオブジェクトを削除したかどうかを知ることはできません。Aweak_ptrは、最後shared_ptrのオブジェクトがいつスコープ外になったかを知っているため、オブジェクトを使用できなくなります。オブジェクトがまだ有効かどうかを尋ねることもできます。expired()メソッドはtrue、オブジェクトが削除されたかどうかを返します。

于 2012-06-22T11:18:44.110 に答える
-1

は絶対に使用しないでくださいdelete this。2 つの理由から、デストラクタはメモリを削除する過程にあり、整理する機会を与えています (OS リソースを解放し、オブジェクトが作成したオブジェクト内のすべてのポインタを削除します)。次に、オブジェクトがスタック上にある可能性があります。

于 2012-06-22T10:02:36.263 に答える