1

ポインタに関していくつか質問があります。初め:

 ObjectType *p; 
 p->writeSomething();

ポインターが初期化されていないときにオブジェクトのメソッドを呼び出すことができるのはなぜですか? そのコードを実行すると、コンソール ウィンドウに "writeSomething()" からの出力が表示されます。2番:

ObjectType *p;
if(p==NULL) 
cout<<"Null pointer";//This is printed out
p = new ObjectType;
delete p;
if(p==NULL)
   cout<<"Null pointer";
else
   cout<<"Pointer is not null";//This is printed out

2 番目の if ステートメントでポインターが null にならないのはなぜですか? また、ポインターがメモリ アドレスを指していないかどうかを確認するにはどうすればよいですか? プログラムの実行が完了したときに一部のメモリが解放されていないかどうかを確認する方法があるかどうかも疑問に思っています。たとえば、コードに 1 つの delete ステートメントを書き忘れた場合。

4

4 に答える 4

7

最初のコードは未定義の動作であり、動作しているように見えることさえあります。呼び出しが静的に解決され、クラスのメンバーにアクセスしていないため、おそらく機能しています。

2 番目のスニペットdeleteはポインタを に設定せずNULL、メモリを解放するだけです。ポインターは、もはや所有していないメモリを指しているため、ぶら下がっています。

于 2012-05-19T09:58:59.220 に答える
3

もちろん、コードは未定義の動作を示しますが、オブジェクトがなくてもメンバー関数を呼び出すことができるように見える理由の例を次に示します。メンバー関数がクラスのメンバーオブジェクトを参照しない場合、それは初期化していないメモリのどの部分にもアクセスする必要はありません。つまり、メンバー関数は本質的に静的です。

ご存じのとおり、メンバー関数は、暗黙的なインスタンス オブジェクト参照引数を持つ通常のフリー関数と見なすことができます。たとえば、次のFooように定義された単純なクラスは、

struct Foo
{
    void bar() { std::cout << "Hello\n"; }
};

単一の無料の関数として実装できます。

void __Foo_bar(Foo * this)
{
    std::cout << "Hello\n";
}

と言うとFoo * p; p->bar();、これは無料の関数呼び出しに相当します__Foo_bar(p);。関数に無効なポインターを渡すことになりますが、関数はポインターを使用しないため、害はありません。

一方、クラスに のようなメンバー オブジェクトがint Foo::n;あり、メンバー関数がそれにアクセスしようとしている場合、実装は にアクセスしようとしますがthis->n、実際には無効なオブジェクトを逆参照しているため、すぐに問題が発生する可能性非常に高くなります。ポインター。

于 2012-05-19T10:30:50.057 に答える
2
delete p;

メモリの割り当てを解除しますが、に格納されているアドレスの値は変更しませんp

標準 C++ には、ポインタが無効なメモリを参照していることを検出する方法はありません。無効なポインターを逆参照しないようにするのは、ユーザーの責任です。

最初の例は未定義の動作です。未定義の動作の考えられる結果の 1 つは、プログラムが意図したとおりに動作することです。繰り返しますが、未定義の動作をするプログラムを書かないようにするのはあなたの責任です。

あなたのコードでwriteSomething()は、おそらく逆参照しない非仮想メンバー関数ですthis。これが、コンパイラーでたまたま機能する理由です。ほとんどの場合、一部のメンバー データ フィールドを参照しようとすると、実行時エラーが発生します。

于 2012-05-19T09:59:07.137 に答える
0

deleteのデストラクタを呼び出し、ObjectTypeその後にメモリの割り当てを解除しますが、明示的にポインタを作成しませんNULL

これは、優れたプログラミングの実践として行わなければならないことです。

于 2012-05-19T10:03:12.727 に答える