2009-03-23 28 views
46

私はC++スタイルのキャストに新しく、私はが私の割り込みサービスルーチンでreal-time-critical deadlineを持っているので、私のアプリケーションのパフォーマンスを損なうC++スタイルのキャストを使用すると心配しています。C++スタイルのキャストからパフォーマンスが低下しましたか?

いくつかのキャストは例外をスローすると聞いたことがあります。

C++スタイルのキャストを使用したいのは、コードをより堅牢にするためです。しかし、の場合、パフォーマンスがになると、おそらくC++スタイルのキャストは使用されず、代わりにCスタイルのキャストを使用するコードのテストに時間がかかります。


C++スタイルのキャストとCスタイルのキャストのパフォーマンスを比較するために厳密なテスト/プロファイリングを行った人はいますか?

あなたの結果は何ですか?

どのような結論を出しましたか?

+0

私はこれに賞金を加えなければならないかもしれません...それは私がどれほど興味を持っているかです。 –

+0

あなたはすでに2つの正確な答えを出しています。 –

+0

ここでの現在の回答は、C++スタイルのstatic_castに実行時のパフォーマンスヒットがないことを示しています。誰かがコメントをしたり、同じパフォーマンスを持つ理由について説明を加えたりしますか? (質問は意図的に漠然としています) –

答えて

77

C++スタイルのキャストを概念的にCスタイルのキャストに置き換えることができれば、オーバーヘッドは発生しません。それができない場合は、dynamic_castのように、それに相当するCがない場合は、料金を支払う必要があります。一例として、

、次のコード:

int x; 
float f = 123.456; 

x = (int) f; 
x = static_cast<int>(f); 

はVC++でキャストの両方で同一のコード生成 - コードは次のとおりです。

00401041 fld   dword ptr [ebp-8] 
00401044 call  __ftol (0040110c) 
00401049 mov   dword ptr [ebp-4],eax 

にキャストする際に投げることができる唯一のC++キャストがdynamic_castです参照。これを避けるには、キャストに失敗した場合に0を返すポインタにキャストします。

+3

C++スタイルのキャストは決してCスタイルのキャストに置き換えられません。何かあれば、それは逆です。標準では、C++スタイルのキャストの動作のみが指定されています。 CスタイルのものはC++のもので記述されています。 – jalf

+1

@jalfはい - 概念的に置き換えられたことを意味します –

+0

ええ、OPがそれを受け入れるなら、それを110%クリアする価値があるかもしれません。 ;) – jalf

39

実行時に余分なコストがかかる唯一のものはdynamic_castです。これは、Cスタイルのキャストでは直接再生できない機能を備えています。だから問題はない。

これを確認する最も簡単な方法は、コンパイラにアセンブラ出力を生成し、生成されたコードを調べるようにコンパイラに指示することです。例えば、どんな健全に実装されたコンパイラでも、reinterpret_castは完全に消えてしまいます。なぜなら、「盲目的に進み、データがこのタイプのふりをしている」という意味だからです。

4

dynamic_castいくつかのチェックを使用して(GCC mailing listでより多くの)愚かな何か、dynamic_castが影響を受けているどのように多くのクラスに依存して1のコストをやってからあなたを防ぐために、実行時に作られ、どのようなクラスは
た場合など、影響を受けていますあなたはキャストが安全だと確信している、あなたはまだreinterpret_castを使用することができます。

+0

reinterpret_castを使用する必要がある場合は、「実装固有の」領域に、おそらく「未定義のビヘイビア」の土地にも賭けています –

+0

reinterpret_castはstatic_castなどと異なるエイリアス規則の対象になることに注意してください。 – leander

16

なぜパフォーマンスが低下するのでしょうか?彼らは正確に Cキャストと同じ機能を実行します。唯一の違いは、コンパイル時に多くのエラーを検出し、ソースコード内で検索する方が簡単だということです。

static_cast<float>(3)は、正確には(float)3に相当し、まったく同じコードを生成します。

float f = 42.0f reinterpret_cast<int*>(&f)は、正確には(int*)&fに相当し、まったく同じコードを生成します。

など。異なるキャストはdynamic_castです。これは例外です。しかし、それはCスタイルのキャストができないことをするからです。その機能が必要でない限り、dynamic_castを使用しないでください。

通常、コンパイラのライターはインテリジェントであると想定するのが安全です。標準に従って同じセマンティクスを持つ2つの異なる式が与えられた場合、それらがコンパイラで同じように実装されると仮定するのが通常安全です。

Oops:2番目の例は、もちろんdynamic_castではなくreinterpret_castである必要があります。今すぐ修正しました。 5.2(

  • const_castを行っ変換:

    §5.4.5:

    ちょうどそれが絶対的に明確にし、[OK]を、ここではC++標準が言うことです.11)

  • a(5.2.9)
  • a static_castは、const_cast
  • reinterpret_cast(5.2.10)、又は
  • const_cast続いreinterpret_cast続きます。

は、キャスト 明示的な型変換の表記を使用して実行できます。 同じセマンティック制限と の動作が適用されます。変換が を上記の ウェイの1つ以上で解釈できる場合、 の解釈が成立していない場合でも、リストの最初に表示される の解釈は となります。

場合はCスタイルのキャストはC++のキャストの面で実装されているのでそう、Cスタイルのキャストは遅くする必要があります。コンパイラはどちらの場合でも同じコードを生成するので、もちろんそうではありませんが、C++スタイルのキャストよりも遅くなる可能性があります。

+0

: "コンパイラで同じように実装されると想定するのは、通常は安全です"。あなたは埋め込み作業やリアルタイムクリティカルな作業をしましたか? –

+0

dynamic_castは参照で操作する場合にのみスローされます。ポインタを処理している場合は、キャストに失敗した場合は0を返します。なぜ、float * to int *変換でdynamic_castを使用するのですか?それは意味をなさない。 –

+0

ああ、もちろん、私はreinterpret_castを意味しました。今修正されました。それを指摘してくれてありがとう。 :) – jalf

3

私は「余分なもの実行時のコストはdynamic_cast "です。コンパイラ固有の違いがあることに注意してください。

現在のコンパイラに対していくつかのバグが報告されていますが、コード生成または最適化はCスタイルとC++スタイルのどちらを使用するかによって若干異なります。static_castキャスト

あなたが心配している場合は、ホットスポットの逆アセンブリを確認してください。それ以外の場合は、必要のないときに動的キャストを避けるだけです。 (RTTIをオフにしても、とにかくdynamic_castは使用できません。)

+0

私はあなたがそれを必要としないときにdynamic_castの使用例を見ることに興味があります。 –

+1

派生クラスにダウンキャストして(たぶんdynamic_castを使用するので)、キャストが合法であることを既に知っているので、代わりにstatic_castを使用できます。 – jalf

+1

@Neil:私は、 "dynamic_castを避けるために"リファクタリングのラインに沿ってもっと意味があると思います。私はトレードオフをしていると知っているし、ときどき別のデザインパターンを選択することで問題を解決することができるため、継承階層に "仮想"を貼り付ける前に、結果をかなり重視する。 – leander

15

あります4 C++スタイルのキャスト:

  • const_cast
  • static_cast
  • reinterpret_cast
  • dynamic_cast

既に述べたように、最初の3は、コンパイル時の操作です。それらを使用するための実行時のペナルティはありません。一方向に宣言されたデータに別の方法でアクセスする必要があることは、コンパイラへのメッセージです。 「これはint*だと言っていましたが、それはsizeof(int) charを指すchar*であるかのように私にアクセスさせてください "または"このデータは読み取り専用で、今は変更しない関数に渡す必要がありますそれはconst参照としてパラメータを取ることはありません。

間違った型にキャストしてデータを破棄する(Cスタイルのキャストでは常に可能性があります)以外に、これらのキャストで最も一般的な実行時の問題は、実際に宣言されたデータです。constはキャスト可能ではありません非const。 constをnon-constにキャスティングし、それを変更することは未定義です。 Undefined means you're not even guaranteed to get a crash

dynamic_castは、実行時の構造であると、実行時のコストを持っている必要があります。

これらのキャストの値は、彼らは、特にあなたが視覚的に突き出し、/からキャストしようとしている、と脳死ツールで検索することができるものと言うことです。私はCスタイルのキャストを使用してそれらを使用することをお勧めします。

+2

実際、 'static_cast'は、Cスタイルのキャスト缶のように(例えば、浮動小数点から整数に、逆もまた同様にキャストするときに)ランタイム演算を行うことができます。 – MikeMB

+1

'static_cast'を使用して浮動小数点と整数を変換するのはなぜですか? 'double d = 5; int i = d; '。変換にはランタイムコストが含まれているかもしれませんが、 'static_cast'を書かなくてもそのコストを支払わなければなりません。 –

+1

暗黙的なナローイング変換が許可されていないコンテキストがあります(例:リストの初期化)、または変換を明示的にしたい場所。例えば。特定のオーバーロードを選択したり、変換が進行中であることを認識していることを(あなたまたはコンパイラに対して)文書化することができます。また、floatからintへの変換は、クラスの明示的な変換演算子/コンストラクタ、または複数の継承を持つ階層内のポインタの上/下のキャストを考えることの一例に過ぎません。 – MikeMB

1

標準的な真実はアセンブリなので、両方を試して、別の論理を得るかどうかを確認してください。

正確に同じアセンブリを取得しても、違いはありません。あなたが本当に古いCのキャストに固執する必要がある唯一の場所は、純粋なCのルーチンとライブラリです。ここでは型キャストのためだけにC++の依存性を導入するのは意味がありません。

注意すべき点の1つは、適切なサイズのコードでキャストがあらゆる場所で発生することです。私のキャリア全体では、ロジックの部分で「すべてのキャスト」を検索したことはありません。キャストを「A」のような特定のTYPEに検索する傾向があり、「(A)」の検索は通常、 "static_cast <A>"のようなものです。タイプのバリデーションなどのために、新しいキャストを使用してください。あなたが決して簡単に行うことができない検索を行うからではありません。

関連する問題