2

キーワードなしで作成されたオブジェクトnewが範囲外になると破棄されるという話をよくしますが、これについて考えると、それは間違っているように思えます。おそらく、変数がスコープ外になるとデストラクタが呼び出されますが、それがスタック内のスペースを占有していないことをどうやって知るのでしょうか? たとえば、次のことを考慮してください。

void DoSomething()
{
  {
    My_Object obj;
    obj.DoSomethingElse();
  }
  AnotherFuncCall();
}

obj実行時にスタックに保存されないことが保証されていますAnotherFuncCallか? 人々はいつもそれを言っているので、彼らの言うことにはいくつかの真実があるに違いobjないAnotherFuncCall. それは公正な仮定ですか?

4

8 に答える 8

3

あなたは2つの異なる概念を混同しています。

はい、オブジェクトのデストラクタは、囲んでいるスコープを離れるときに呼び出されます。これは規格によって保証されています。

いいえ、言語の実装がスタックを使用して自動ストレージ (つまり、「スタック割り当てオブジェクト」と呼ばれるもの) を実装するという保証はありません。

ほとんどのコンパイラは固定サイズのスタックを使用しているため、あなたの質問が何であるかさえわかりません。これは通常、固定サイズのメモリ領域として実装されます。スタックを「クリーンアップ」するために必要なのはポインタの移動だけです。これは、そのメモリがすぐに再び使用されるためです。

したがって、スタックを実装するために使用されるメモリ領域はサイズが固定されているため、オブジェクトが使用するメモリを 0 などに設定する必要はありません。再び必要になるまでそこに住むことができ、害はありません。

于 2012-06-22T20:03:25.863 に答える
1

人々が言うことは確かに真実です。オブジェクトはまだメモリ位置に残ります。ただし、スタックが機能する方法は、オブジェクトがスタックからメモリスペースを取得しないことを意味します。

スタックにメモリが割り当てられると通常は、スタックポインタデクリメントされsizeof(type)、変数がスコープから外れてオブジェクトが解放されると、スタックポインタインクリメントされるため、スタックに割り当てられるデータの有効サイズが小さくなります。実際、データは元のアドレスに残っており、破棄または削除されることはありません

そして明確にするために、C ++標準はこれについてまったく何も述べていません!C ++標準は、プラットフォーム固有の 実装の詳細であるため、メモリ割り当ての意味でスタックまたはヒープと呼ばれるものを完全に認識していません。

于 2012-06-22T20:07:03.857 に答える
1

ローカル スコープで「スタック上」に作成されたオブジェクトには、自動保存期間と呼ばれるものがあります。規格は次のように述べています。

C++03 3.7.2 自動保存期間

1/ 明示的に auto または register と宣言されたローカル オブジェクト、または明示的に static または extern と宣言されていないローカル オブジェクトは、自動ストレージ期間を持ちます。これらのオブジェクトのストレージは、それらが作成されたブロックが終了するまで続きます。

2/ [注: これらのオブジェクトは、6.7 で説明されているように初期化および破棄されます。]

これらのオブジェクトの破壊について:

6.7 宣言文

2/ 自動保存期間 (3.7.2) を持つ変数は、それらの宣言ステートメントが実行されるたびに初期化されます。ブロックで宣言された自動保存期間を持つ変数は、ブロックの終了時に破棄されます (6.6)。

したがって、標準によると、ローカル スコープを持つオブジェクトがスコープ外になると、デストラクタが呼び出され、ストレージが解放されます。

ストレージがスタック上にあるという天気かどうかは、標準では述べていません。どこにいても、ストレージが解放されたと言っているだけです。

一部のアーキテクチャには、PC と同じ意味でのスタックがありません。C++ は、あらゆる種類のプログラマブル デバイスで動作することを意図しています。そのため、スタック、ヒープなどについては何も言及されていません。

Windows とユーザー モード コードを実行する一般的な PC タイプのプラットフォームでは、これらの自動変数はスタックに格納されます。これらのスタックは固定サイズで、スレッドの開始時に作成されます。それらがインスタンス化されると、それらはスタック上のより多くのスペースを占有し、スタック ポインターが移動します。これらの変数を十分に割り当てると、スタックがオーバーフローし、プログラムは醜い死に方をします。

これを Windows PC で実行してみて、例で何が起こるかを確認してください。

int main()
{
    int boom[10000000];
    for( int* it = &boom[0]; it != &boom[sizeof(boom)/sizeof(boom[0])]; ++it )
        *it = 42;
}
于 2012-06-22T20:10:28.817 に答える
1

オブジェクトが作成されたスタックの場所に依存すると思います。それが一番下にあった場合(スタックが下に成長すると仮定)、2番目の関数が破棄されたオブジェクトスペースを上書きする可能性があると思います。オブジェクトがスタック内にある場合、それ以降のすべてのオブジェクトをシフトする必要があるため、おそらくそのスペースが無駄になります。

于 2012-06-22T19:59:19.213 に答える
1

人々はいつもそれを言っているので、彼らの言うことにはいくつかの真実があるはずです. それは公正な仮定ですか?

正解です。この最後の質問は、スタックについて何も述べていないことに注意してください」。実装がスタックを使用するか、それ以外のものを使用するかは、実装次第です。

于 2012-06-22T20:05:01.853 に答える
1

スタックは動的に割り当てられたり割り当て解除されたりするのではなく、ただそこにあります。オブジェクトのコンストラクタとデストラクタは呼び出されますが、メモリは返されません。

于 2012-06-22T20:02:29.623 に答える
0
how do we know that it is no longer taking up space in the stack?

私たちはしません。動作するかどうかを確認する方法はありますが、それらはアーキテクチャと ABI 固有のものです。通常、関数は呼び出し元に制御を返すときに、スタックにプッシュしたものをすべてポップします。C/C++ が保証するのは、高レベル オブジェクトがスコープを離れるときにそのデストラクタを呼び出すことです (ただし、MSVC 6 のような一部の古い C++ には、そうでないときにひどいバグがありました)。

Is it guaranteed that obj will not be saved on the stack when AnotherFuncCall is executed? 

いいえ。 ABI の要件に準拠している限り、スタック フレームをいつどのようにプッシュおよびポップするかは、コンパイラによって決定されます。

于 2012-06-22T20:15:05.557 に答える
0

スタック上のローカル変数は余分なメモリを必要としません。システムは各スレッドのスタックからいくらかのメモリを提供し、スタック上の変数はその一部だけを使用します。スコープを使い果たした後、コンパイラはスタックの同じ部分を他の変数に再利用できます (後で同じ関数で使用されます)。

于 2012-06-22T20:05:06.770 に答える