0

次の例を考えてみましょう

class Foo{
  public:
    Foo(int i):x(i){}
    int x;
};

void
bar(Foo *p2)
{
  delete p2; 
  p2 = new Foo(2); 
}  

int
main()
{
  Foo *p1 = new Foo(1);
  cout<<p1->x;
  bar(p1);
  cout<<p1->x;
}

私の理解では、ポインタ変数はスタックに格納され、「指している」ヒープ上に動的に割り当てられたメモリへのアドレスが含まれています。ここで、関数にポインターを渡すと、スタック上に 2 番目のポインターが作成され、最初のポインターと同じメモリ アドレスを指します。bar() で p2 を削除して新しいメモリを割り当てると、p1 と p2 は別のアドレスを指しているはずですよね?

ただし、このコードをコンパイルすると、出力として 1 と 2 が得られます。これは、p2 が p1 が既に指しているのと同じメモリ セルを割り当てることができたからですか、それとも見逃したことがありますか?

4

2 に答える 2

1

これは、p2がp1がすでに指しているのと同じメモリセルを割り当てることができたためですか、それとも私が見逃したものがありますか?

あなたは何も逃しませんでした。このプログラムの動作が未定義であることを正しく識別しました。定義上、を含むすべてのものを印刷できます2

あなたの実行では、それが印刷されるのは偶然の一致(そしておそらくあなたが特定した偶然の一致)だけです2。既存のの前後にnew int(47)追加することで、偶然の一致の連鎖を混乱させる可能性があります。deletenew

プログラムがそのように動作することを望むが、定義された動作を通じて、barの定義にこの小さな変更を加えることができます。

void
bar(Foo*& p2)

これにより、値ではなく参照によってパラメータが渡されます。これにより、内部の変数への変更が内部の`mainに反映されます。p2barp1

于 2012-07-14T02:01:03.973 に答える
0

あなたのサンプルを除いて、ポインター変数は必ずしもスタック上にあるとは限らず、それらが参照するアドレスは必ずしもヒープ上にあるとは限りません(ただし、 new と malloc は両方ともヒープ上のアドレスを返します)。ポインター変数とそれが参照するアドレスの両方が、スタック、ヒープ、グローバル/静的変数領域、さらには ROM にある可能性があります。あなたの説明の残りは正しいですが、あなたが観察する動作は未定であり、再現可能であると期待するのは本当に非常に危険です. 変更、異なるランタイム バージョン、マルチスレッドの状況、異なるアーキテクチャまたは別のコンパイラでのコンパイルは、結果を完全に変更する可能性があります: ランダム値またはクラッシュ。

于 2012-07-14T16:31:32.167 に答える