ループがあり、このループ内で新しいスタック変数を作成すると(ヒープ上に割り当てず、ループ本体内で宣言された変数を保持する変数ではありません)、このオブジェクトのデストラクタは、次の反復が始まる前に呼び出されることが保証されます。コンパイラによるループの展開はそれについて何かを変更しますか?
ループがあり、このループ内で新しいスタック変数を作成すると(ヒープ上に割り当てず、ループ本体内で宣言された変数を保持する変数ではありません)、このオブジェクトのデストラクタは、次の反復が始まる前に呼び出されることが保証されます。コンパイラによるループの展開はそれについて何かを変更しますか?
回答:
からn4800
:
§6.3.3 ブロック範囲:
ブロック(8.3)で宣言された名前は、そのブロックに対してローカルです。ブロックスコープがあります。その潜在的なスコープは、宣言の時点(6.3.2)で始まり、そのブロックの終わりで終わります。ブロックスコープで宣言された変数はローカル変数です。
§10.3.6 デストラクタ:
オブジェクトが作成されたブロックが終了すると、デストラクタが暗黙的に呼び出されます[...](8.7)
§4.1.1 抽象マシン:
この規定は、「as-if」ルールと呼ばれることもあります。これは、実装がこのドキュメントの要件を無視できるということです。プログラム。
[エンファシス鉱山]
あ、はい。変数がループの終わり(ブロック)でスコープ外になるため、プログラムの動作を監視している人が知る限り、そのデストラクタが呼び出されます。
call
編集されない場合もあります。または、それらが実質的に(as-ifルールで)何もしない場合、生成されたそのようなデストラクタのアセンブリがない可能性があります。
はい。変数を宣言する「ブロック」を検討すると、視覚化するのが簡単になります。ループはそれ自体がブロックであり、閉じ括弧に達すると、次の反復の前に、ループで宣言されている自動ストレージ変数のすべてのデストラクタが呼び出されます。
コンパイラーによるループのアンロールは、それについて何かを変えるのでしょうか?
経験則として、コンパイラーが最適化するものについては考えないでください。最適化するために何をしても、プログラムの動作を保証する必要があるためです。その場合、ループの展開は、それが起こってもその効果に何も変更しません。
[class.copy.elision]
for(...) X x{};
、x
オブジェクトは各反復で構築され、破壊されます。ライブデモ。関連する標準セクションはstmt.iter / 2です。
[stmt.iter]
完全に同等です(強調文):「反復ステートメント内のサブステートメントが単一ステートメントであり、複合ステートメントではない場合、複合ステートメントに書き換えられたかのようになります。元のステートメント。 " 本質的に、単一のステートメントで中括弧がある場合とない場合は、まったく同じことを意味し、中括弧は暗黙的です。わかりやすくするために省略しました。
デストラクタはすべての反復で呼び出されます。したがって、場合によっては、ループ内ではなくループ外で変数を宣言する方が高速です。次の場合を想定します。
std::string temp;
for(int i = 0; i < 10; ++i){
temp = arr[i];
doSomething(temp);
}
ループの使用時に、デストラクタは呼び出されません。それは単に上書きしますtemp
。
しかしstd::string temp = arr[i]
、コンストラクタを使用すると、反復ごとにデストラクタが呼び出されます。非常に頻繁に実行されるループがある場合、これは少しランタイムを追加すると思います。
もちろん、dtorは反復の終わりに呼び出され、ループのアンロールはこの動作を変更するべきではありません。他の最適化(最適化はプログラムの動作を変更するべきではありません)と同じです。 。