[解決済み] C++0xで "while(1); "を排除する最適化
質問
更新しました!下記をご覧ください。
C++0xでは、次のスニペットに対してコンパイラが"Hello"を表示できると聞いたり読んだりしたことがあります。
#include <iostream>
int main() {
while(1)
;
std::cout << "Hello" << std::endl;
}
どうやらスレッドと最適化能力に関係があるようです。これは多くの人を驚かせることができそうですが。
なぜこれを許可する必要があったのか、どなたか良い説明をお持ちの方はいらっしゃいますか?参考までに、最新の C++0x ドラフトでは、以下のように書かれています。
6.5/5
for文の場合、for-init文の外側にあるループのこと。
- ライブラリI/O関数を一切呼び出さない。
- volatileオブジェクトにアクセスしたり変更したりしない。
- 同期操作(1.10)やアトミック操作(第29項)を行わない。
は、実装によって終了することが想定される。[注:これはコンパイラによる変換を可能にするためのものです。 終了が証明できない場合でも、空のループの削除などのメーションが可能です。- エンドノート ]。
編集する
この洞察に満ちた記事 その基準文について
<ブロッククオート残念ながら、undefined behaviorという言葉は使われていません。しかし、「コンパイラはPと仮定してよい」と書かれている場合、not-Pのプロパティを持つプログラムは未定義のセマンティクスを持っているということを暗に示しているのです。
上記のプログラムに対して、コンパイラは "Bye" と出力してよいのでしょうか?
さらに洞察に満ちた このスレッド これはC言語の類似の変更に関するもので、上記のリンク先の記事にあるGuyが始めたものです。他の有用な事実の中で、彼らはC++0xにも適用されると思われる解決策を提示しています( 更新 : n3225ではもう使えません - 下記参照!)
endless:
goto endless;
コンパイラは、ループではなく、ジャンプなので、それを最適化することは許されないようです。別の人が、C++0xとC201Xの変更案をまとめています。
<ブロッククオートループを書くことで、プログラマは次のことを主張している。 どちらか その ループは目に見える動作(I/Oの実行、アクセス)をします。 揮発性オブジェクト、同期またはアトミック操作の実行)。 または 最終的に終了すること。 その前提に反すると 副作用のない無限ループを書くことで、私は嘘をついていることになります。 コンパイラは、私のプログラムの動作が未定義であることを示します。 (もし私が幸運なら。 コンパイラが警告してくれるかもしれません)。 言語が提供しない (無限ループを表現する方法がない? 目に見える動作
2011年3月1日、n3225で更新。委員会は、1.10/24にテキストを移動し、次のように述べています。
<ブロッククオート実装は、どのスレッドも最終的に以下のいずれかを行うことを想定してよい。
- を終了させる。
- ライブラリI/O関数を呼び出す。
- volatileオブジェクトへのアクセスまたは修正、または
- 同期操作またはアトミック操作の実行。
は
goto
トリックは
ではなく
はもう使えない!
解決方法は?
<ブロッククオートなぜこれを許可する必要があったのか、どなたか良い説明をお持ちの方はいらっしゃいませんか?
はい、Hans Boehmはその根拠を次のように示しています。 N1528: なぜ無限ループでは未定義の動作になるのですか? これはWG14の文書ですが、その根拠はC++にも適用され、この文書はWG14とWG21の両方に言及されています。
<ブロッククオートN1509が正しく指摘するように、現在の草案は本質的に 6.8.5p6では無限ループが未定義な動作になっています。大きな問題点として そのため、潜在的なコードの移動が可能になります。 非終了ループ 例えば、以下のようなループがあるとします。 ここで、countとcount2はグローバル変数(またはそのアドレスを持つ)である。 pはローカル変数で、そのアドレスはまだ取得されていない。
for (p = q; p != 0; p = p -> next) {
++count;
}
for (p = q; p != 0; p = p -> next) {
++count2;
}
この2つのループを統合して、次のようなループに置き換えることは可能でしょうか?
for (p = q; p != 0; p = p -> next) {
++count;
++count2;
}
6.8.5p6 の無限ループの特別な免除がなければ、これは は許されないでしょう。最初のループが終了しないのは、q が循環リストを指している場合、オリジナルは決して count2 に書き込まれません。したがって をアクセスする別のスレッドと並列に実行することができます。 を更新する。これは変換されたバージョンではもはや安全ではありません。 無限ループにもかかわらず count2 にアクセスする。このため 変換はデータレースを引き起こす可能性があります。
このような場合、コンパイラがこのような問題を解決できる可能性は極めて低いです。 ループの終了を証明するためには、qがループを指していることを理解しなければなりません。 を非周期リストに変換することは、ほとんどの場合、その能力を超えていると思います。 主流のコンパイラは、プログラム全体がないと不可能なことが多い。 の情報です。
非終了ループによる制限は、そのループが終了する前に、そのループが終了してしまうという制限です。 コンパイラが最適化できない終端ループの最適化。 の最適化だけでなく、終了を証明することもできます。 非終了ループ 前者の方がはるかに一般的です。 また、後者の方が最適化する上で興味深い場合が多い。
また、ループ変数が整数であるforループも明らかに存在します。 コンパイラが終端を証明することが困難で、かつ ループを再構築することは困難です。 6.8.5p6を使用しない場合。のようなものでも
for (i = 1; i != 15; i += 2)
または
for (i = 1; i <= 10; i += j)
を処理することは自明ではないようです。(前者の場合、基本的な数 終了を証明するためには理論が必要であり、後者の場合は の値について何か知っている必要があります。ラップアラウンド は、符号なし整数の場合、この推論をさらに複雑にする可能性があります)。
この問題は、ほとんどすべてのループ再構築に適用されるようです。 コンパイラの並列化や キャッシュ最適化変換は、今後ますます増加すると思われます。 の重要性が増しており、数値計算コードでは既に重要な場合が多い。 これは、次のような利点に対して、かなりのコストになりそうです。 無限ループを最も自然な形で書けるようになる。 特に、ほとんどの人は意図的に無限ループを書くことはないので。
C言語と大きく違うのは C11 では、定数式である式を制御するための例外が用意されている これはC++とは異なり、あなたの具体的な例をC11でうまく定義しています。
関連
-
[解決済み] テスト
-
[解決済み】非静的メンバ関数への参照を呼び出す必要がある
-
[解決済み】識別子 "string "は未定義?
-
[解決済み】文字列関数で'char const*'のインスタンスを投げた後に呼び出されるterminate [閉店].
-
[解決済み】標準ライブラリにstd::endlに相当するタブはあるか?
-
[解決済み】C++ - ステートメントがオーバーロードされた関数のアドレスを解決できない。
-
[解決済み】c++で.txtファイルから2次元の配列に読み込む
-
[解決済み] Bashでの単一行whileループの構文
-
[解決済み】f(i = -1, i = -1)の挙動が未定義なのはなぜ?
-
[解決済み] なぜこのループは「warning: iteration 3u invokes undefined behavior」を生成し、4行以上出力するのでしょうか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】コンストラクターでのエラー:識別子を期待されますか?
-
[解決済み】非静的メンバ関数への参照を呼び出す必要がある
-
[解決済み] error: 'ostream' does not name a type.
-
[解決済み】「corrupted size vs. prev_size」glibc エラーを理解する。
-
[解決済み】'cout'は型名ではない
-
[解決済み】c++でstd::vectorを返すための効率的な方法
-
[解決済み】「Expected '(' for function-style cast or type construction」エラーの意味とは?
-
[解決済み] gdbを使用してもデバッグシンボルが見つからない
-
[解決済み] 変数サイズのオブジェクトが初期化されないことがある c++
-
[解決済み】ループや条件文を使わずに1~1000を印刷する