1

Fooコンストラクターを使用してクラスを作成するとしFoo(int)ます。そして、私はこのコードを持っています:

Foo a(i), b = a + Foo(2);

コード内で定数を使用してコンストラクターを呼び出した場合、たとえばFoo(2)、コンパイラーはコンストラクターを一度実行して実行時に結果を保存しますか?それとも実行時に実行されますか? 構造体/クラスにPODデータ型のみが含まれているかどうかは同じですか?

実行時に実行されると仮定すると(私はそうなると思います)、コンパイル時に実行する方法、または実行した場合と同じ効果を持つ方法はありますか?

編集:申し訳ありませんが、私は自分自身を明確にしませんでした。Foo(2)完全に不変であるコードの部分を参照しています。また、私は C++11 を利用できません (私は GCC 4.1 を使用しており、アップグレードできません) constexpr

4

6 に答える 6

3

a静的な初期化である を使用することは可能constant initializationですが、それが起こるためには:

  1. iほとんどが定数式
  2. Foo::Foo(int)でなければなりませんconstexpr
  3. によって使用される他のすべての関数/ctorFoo:Foo(int)も である必要がありますconstexpr

同じことがあなたの場合にbもほとんど当てはまります。Foo(2)constexprFoo::operator+(Foo const &)Foo operator+(Foo const &, Foo const &)constexpr

定数式の定義は、C++11 標準の §5.19 にあります。詳細を調べたい場合に備えてください。私の当面の推測では、Fooがかなり単純な場合、 についてはおそらく可能ですaが、 については確信が持てませんb

于 2012-05-24T05:19:50.753 に答える
3

コンストラクター Foo(int) を使用してクラス Foo を作成するとします。そして、私はこのコードを持っています:

Foo a(i), b = a + Foo(2);

コード内で定数を使用してコンストラクターを呼び出した場合、コンパイラーはコンストラクターを 1 回実行し、結果を実行時に保存しますか?それとも実行時に実行されますか?

これには 2 つのレベルがあります。

  • 完璧なオプティマイザーの標準に関しては可能であり、合法的ですか?専門家が無制限の努力と天才で潜在的に行うことができるすべてを達成します-これをコンパイル時に行うこと、および
  • 標準で必要/保証されているコンパイル時の動作です。

iコンパイル時間は一定ですか?そうでない場合、i渡された値がFoo::Foo(i)その動作に影響を与える (データ メンバーの値に影響するか、ロギングなどの副作用に影響する) 場合、コンパイル時に Foo(i) を構築することは本質的に不可能であることは明らかです。が定数の場合iでも、本質的に不可能な場合があります。たとえば、コンストラクターの実装が現在の時刻に基づいて動作する場合や、他のランタイム データを参照する必要がある場合などです。このような問題はFoo(2)、コンパイル時に評価できない場合もあります。

iが一定で、Fooのコンストラクターが他の実行時のみのデータに依存しない場合、最適化することができますしかし、あなたのコードには、C++ 標準が最適化を試みることさえ必要とするものは何もありません。同じことが s+で呼び出される演算子にも当てはまりFooます...最適化することは合法かもしれませんが、確かに必須ではありません。

Foo(i)実際には、現在の主流のコンパイラのほとんどがfor compile-time constantの単純なケースを最適化することを期待してiいますが、追加を解決することによって挑戦されます。本当に知りたい場合は、さまざまな最適化レベルでコンパイラを試してみてください....

実行時に実行されると仮定すると(私はそうなると思います)、コンパイル時に実行する方法、または実行した場合と同じ効果を持つ方法はありますか?

はい... からいくらかのマイレージを取得できます。constexprこれは、C++ 11 で導入されたキーワードであり、コンパイル時に特定の値を解決する必要があることをコンパイラに伝えます (constexprコンパイラが必要としない変数/値の場合)コンパイル時にサポートすると、エラーが報告されます)。

次に、テンプレートを使用してコンパイル時の操作を表現できることがよくあります。その方向で自分自身を開始するには、「C++ テンプレート階乗コンパイル時間」などを検索して、基本的な計算をコーディングする方法を確認することをお勧めします。

于 2012-05-24T06:42:07.453 に答える
2

「as-if」ルールが適用されます。これは、プログラムの観察可能な動作が標準で説明されているものと同じであれば、コンパイラーは好きなことを何でもできるということです。

もしも:

  • のコンストラクターはFooTU に表示されます。
  • デストラクタ~Fooも同様です。
  • どちらも副作用はありませんが、
  • それらの結果は、実行時に解決する必要があるものには依存しません (時間や、コードが実行される時点で変更されている可能性があることがわかっている非 const オブジェクトの値など)。
  • operator+RHS のアドレスを不明なコードに「エスケープ」させたり、そのアドレスを観察可能な動作 (出力など) に使用したり、オブジェクトが実際にそこにあることを必要とするその他のことを行ったりしません。

その場合、十分に賢いオプティマイザーはFoo(2)一時的なものを完全に排除しoperator+、RHS のデータ メンバーを使用する場所はどこでも、それらのメンバーが持つことがわかっている値を使用するだけです。

または、それほど最適化されていない方法として、値をFooプログラムのデータ セクションの のインスタンスのレイアウトに配置し、それを として使用することもできFoo(2)ます。実行時に結果を保存するということは、それを意味していると思います。

このような最適化が実際に行われるかどうかは、完全に実装固有であり、使用するコンパイラとフラグに依存します。コードを逆アセンブルして、実際に何が起こるかを確認します。

Foo(2)次のようなことを行うと、C++03 で が 1 回だけ計算されるようにすることができます。

static Foo foo2(2);
Foo a(i), b = a + foo2;

foo2(標準に従って) コードが最初に実行される実行時に計算されます。繰り返しになりますが、コンパイラは「as-if」ルールを呼び出して、コンパイル時に計算の一部またはすべてを実行できますが、これも必須ではありません。

于 2012-05-24T08:52:00.263 に答える
0
Foo a(i), b = a + Foo(2);

この初期化は、コンパイル時ではなく、実行時に行われます。

コンパイル時の初期化は、組み込み型の場合にのみ発生します。初期化子がコンパイル時に計算できる場合、またはグローバル変数として、またはとして宣言されている場合ですstatic。後者の2つのケースでは、コンパイル時にゼロ初期化されます。私はこれをここで詳細に説明しました:

于 2012-05-24T05:03:58.207 に答える
0

コンパイルされたコードは、実行プロセス中のさまざまな時点で呼び出される場合があります。コードがコンパイルされると、Foo(2) の値は不変になる可能性があります。

于 2012-05-24T05:06:11.043 に答える
-1

これは実行時に発生します。コンパイル時に発生させたい場合は、値をハードコーディングする必要があります。

于 2012-05-24T05:05:08.433 に答える