6

同じコードを最適化を完全に無効にして ( g++ -O0) コンパイルし、次に最適化を完全に有効にして( ) コンパイルするg++ -O3と、ソース コード自体のロジックをどのように変更できますか?

たとえば、コンパイラは次のことができます。

これら 2 つの最適化により、元のソース コードの整合性に影響を与えることなく、コードの実行速度が向上します。これらの最適化なしで実行されるコードは、それらを有効にして実行されます。

ただし、コンパイラの最適化はコード ロジックにも影響を与える可能性があります。私が知っている2つの例を次に示します。

これらについて学べたことは非常に驚き、幸運でした。なぜなら、これらは間違った状況で大きな落とし穴になる可能性があるからです。

知りたいのですが、C++ コンパイラの最適化がコード ロジックに影響を与える他のケースはありますか? 特に g++ コンパイラでの c++11 (未定義の動作なし) に関する情報を探していますが、他のコンパイラのヒントは大歓迎です。

4

2 に答える 2

8

「仮定」ルール:

実装は、プログラムの観察可能な動作から判断できる限り、この国際標準の要件を無視してもかまいません。たとえば、実際の実装では、式の値が使用されておらず、プログラムの観察可能な動作に影響を与える副作用がないと推測できる場合、式の一部を評価する必要はありません。

ただし、標準では、許可され、「as-if」ルールを破る 1 つの最適化について言及しています。

特定の基準が満たされると、オブジェクトのコピー/移動コンストラクターおよび/またはデストラクタに副作用がある場合でも、実装はクラス オブジェクトのコピー/移動構築を省略できます。このような場合、実装は、省略されたコピー/移動操作のソースとターゲットを、同じオブジェクトを参照する 2 つの異なる方法として扱い、そのオブジェクトの破棄は、2 つのオブジェクトが削除されていた時間のうちの遅い方の時点で発生します。最適化なしで破棄されます。

— クラスの戻り値の型を持つ関数の return ステートメントで、式が関数の戻り値の型と同じ cvunqualified 型を持つ非揮発性自動オブジェクト (関数または catch 句のパラメーター以外) の名前である場合、自動オブジェクトを関数の戻り値に直接構築することにより、コピー/移動操作を省略できます

— throw 式で、オペランドが非 volatile 自動オブジェクト (関数または catch 句パラメーター以外) の名前であり、そのスコープが最も内側の try ブロックの末尾を超えて拡張されていない場合 (存在する場合) 1 つ)、オペランドから例外オブジェクト (15.1) へのコピー/移動操作は、自動オブジェクトを直接例外オブジェクトに構築することによって省略できます。

— 参照 (12.2) にバインドされていない一時クラス オブジェクトが同じ cv 非修飾型のクラス オブジェクトにコピー/移動される場合、一時オブジェクトを省略したコピー/移動の対象

— 例外ハンドラーの例外宣言 (条項 15) が、例外オブジェクト (15.1) と同じタイプ (cv 修飾を除く) のオブジェクトを宣言する場合、コピー/移動操作は、例外宣言を処理することによって省略できます。 exception-declaration によって宣言されたオブジェクトのコンストラクタとデストラクタの実行を除いて、プログラムの意味が変更されない場合は、例外オブジェクトのエイリアスとして。

于 2012-10-18T04:22:57.187 に答える
1

「未指定の動作」とは、実装が可能な動作のいずれかを自由に選択できる動作です。このような場合、オプティマイザーが選択に影響を与える可能性があります。

簡単な例は、関数への引数が評価される順序です。最適化されていないビルドでは、左から右または右から左を使用できますが、最適化されたビルドでは、引数が「混在した」順序で評価される場合があります。正当な理由は、引数間で共通部分式の最適化の機会を最大化することです。

これらの引数のいずれかに顕著な副作用がある場合、コード ロジックが変更されますが、それがバグであるかどうかはケースごとに異なります。

于 2012-10-18T12:03:16.603 に答える