変数のスコープと存続期間の間にはどのような関係がありますか?変数がスコープ外の場合、そのメモリを別の変数で上書きできるか、または関数が終了するまで予約されているスペースです。
以下のコードが実際に機能するかどうか、または*pが未定義である可能性があるかどうかを知りたいので私は尋ねています
foo() {
int *p;
{
int x = 5;
p = &x;
}
int y = *p;
}
スコープとは何ですか?
スコープは、変数にアクセスできるコードの領域またはセクションです。
生涯とは何ですか?
ライフタイムは、オブジェクト/変数が有効な状態にある期間です。
の場合、自動/ローカル非静的変数Lifetime
はそれらに制限されますScope
。
つまり、自動変数は、それらが作成されたscope( {
、 )が終了すると、自動的に破棄されます。}
したがって、名前はそもそも自動です。
コード例の何が問題になっていますか?
したがって、はい、コードには未定義動作があります。
この例では、スコープ*p
は作成後の関数本体全体です。
ただし、x
は非静的ローカル/自動変数であるため、スコープが終了すると、そのスコープで終了します。つまり、スコープが終了すると、それが作成されx
た閉じ中括弧が存在しなくなります。もう存在しないものを指しています。 }
x
*p
技術的x
にはその範囲を超えて存在しないことに注意してください。ただし、コンパイラがの内容を削除せず、ポインタを介して範囲を超えたx
内容にアクセスできる可能性があります(ただし、これを行うコード)は有効なC++コードではありません。これは、未定義動作を呼び出すコードです。つまり、何かが起こる可能性があり(無傷であることに価値があるとさえ思われるかもしれません)、そのようなコードから観察可能な動作を期待するべきではありません。x
x
識別子が指定する異なるエンティティごとに、その識別子はスコープと呼ばれるプログラム テキストの領域内でのみ表示されます (つまり、使用できます)。同じ識別子で指定された異なるエンティティは、スコープが異なるか、名前空間が異なります。
.
オブジェクトの存続期間は、プログラム実行の中で、そのオブジェクト用にストレージが確保されることが保証されている部分です。
あなたの場合x
、ブロックに対してローカルであり、その寿命もそうであるx
ため、ブロック外の名前でアクセスすることはできません。また、その寿命はそのブロックに制限されているため、x
ブロックを離れた後、アドレスは予約されなくなります。未定義の動作が発生します。
一方、たとえば、static
ローカル変数について言えば、この場合、スコープはブロックに対してローカルであるため、その名前でブロック外にアクセスすることはできませんが、有効期間はプログラム全体であるため、使用できます実行中のプログラム内の変数のアドレス。この例は違いを理解するのに役立ちます。
オブジェクト(つまり、値を格納する実際の基礎となるもの)には存続期間があります。
変数(つまり、オブジェクトを参照するために使用されるもの)にはスコープがあります。
いずれにせよ、y = *p
未定義の動作を呼び出します。によって参照されるオブジェクトx
は自動x
であり、スコープ外になるとその存続期間は終了します。
変数のスコープと存続期間の間にはどのような関係がありますか?
Oliが述べたように、変数にはスコープとオブジェクトの有効期間があります。変数のスコープとその存続期間はバインドされていますが、作成されたスコープを超えて存続期間が延長されるオブジェクトを持つことができます。
int* f() {
int *p // Variable p
= new int(1); // object (call it x)
return p; // p scope ends, p lifetime ends, x survives
}
int main() {
int *q // Variable q
= f(); // ... points to x
delete q; // x lifetime ends, q is in scope, q is alive
}
あなたの特定のケースでは、x
変数はそれが作成されたスコープが閉じられたときにその存続期間を終了するので、未定義の振る舞いがあります。
変数がスコープ外の場合、そのメモリを別の変数で上書きできるか、または関数が終了するまで予約されているスペースです。
これは実装の詳細です。変数へのアクセスはすべての場合で未定義の動作であり、すべての場合が等しくなければならないわけではないため、変数に自明でないデストラクタがある場合はスコープの最後で呼び出されるため、メモリが存在するかどうかは関係ありません。オブジェクトはもうありません。そうは言っても、多くの場合、コンパイラは変数がスコープ外になったときに関数内のメモリを解放しません(つまり、フレームポインタを再設定しません)が、同じスペースを再利用して同じ関数内の他の変数を保持する場合があります。
あなたのプログラムを実行しましたが、出力は 5 です。出力はまだ 5 ですが、x 変数は 2 番目の '}' の後に破棄されます。これは、メモリの場所が他の変数によって上書きされないためです。 2 番目のスコープの終了時、'x' が以前に所有していたメモリ ロケーションが上書きされる可能性が非常に高くなります。
int x = 5;
*p = &x;
} // x lifetime ends after this.but the number '5' is still there in that memory.
//but it is possible to assign this memory (which previously belong to x) to a new var.
標準では、スコープを離れるとメモリを上書きできると定義しています。コンパイラの実装により、予約および解放されます。コンパイル時の最適化により、スタックの割り当てが移動する可能性があるため、順序が反映されなくなります。
コードは未定義の動作を引き起こすため、使用しないでください。値 p が指す値を取得した後に y の値を書き込むため、コードは実際に機能する可能性があります。