static_cast
関数はCスタイルまたは単純な関数スタイルのキャストよりも優先されるべきだと聞いたことがあります。これは本当ですか?どうして?
static_cast
関数はCスタイルまたは単純な関数スタイルのキャストよりも優先されるべきだと聞いたことがあります。これは本当ですか?どうして?
回答:
主な理由は、古典的なCのキャストたちが呼んでいるものの区別をしないということですstatic_cast<>()
、reinterpret_cast<>()
、const_cast<>()
、とdynamic_cast<>()
。これらの4つは完全に異なります。
A static_cast<>()
は通常安全です。言語の有効な変換、またはそれを可能にする適切なコンストラクタがあります。少し危険なのは、継承されたクラスにキャストダウンするときだけです。オブジェクトのフラグのように、言語の外部で、オブジェクトが実際にそれが主張する子孫であることを確認する必要があります。A dynamic_cast<>()
は、結果がチェックされる(ポインター)か、起こり得る例外が考慮される(参照)限り、安全です。
一方reinterpret_cast<>()
、A (またはconst_cast<>()
)は常に危険です。あなたはコンパイラーに次のように伝えます:「信頼してください:これはaのようには見えませんfoo
(これは変更可能ではないように見えます)が、そうです」。
最初の問題は、大規模で分散しているコードの断片を見て、すべてのルールを知らないと、Cスタイルのキャストでどれが発生するかを見分けることがほとんど不可能であることです。
これらを仮定しましょう:
class CDerivedClass : public CMyBase {...};
class CMyOtherStuff {...} ;
CMyBase *pSomething; // filled somewhere
これで、これら2つは同じ方法でコンパイルされます。
CDerivedClass *pMyObject;
pMyObject = static_cast<CDerivedClass*>(pSomething); // Safe; as long as we checked
pMyObject = (CDerivedClass*)(pSomething); // Same as static_cast<>
// Safe; as long as we checked
// but harder to read
ただし、このほとんど同じコードを見てみましょう。
CMyOtherStuff *pOther;
pOther = static_cast<CMyOtherStuff*>(pSomething); // Compiler error: Can't convert
pOther = (CMyOtherStuff*)(pSomething); // No compiler error.
// Same as reinterpret_cast<>
// and it's wrong!!!
ご覧のとおり、関係するすべてのクラスについて多くを知らなければ、2つの状況を簡単に区別する方法はありません。
2番目の問題は、Cスタイルのキャストを見つけるのが難しいことです。複雑な式では、Cスタイルのキャストを表示するのが非常に難しい場合があります。本格的なC ++コンパイラのフロントエンドがなければ、Cスタイルのキャストを見つける必要がある自動化ツール(たとえば、検索ツール)を書くことは事実上不可能です。一方、「static_cast <」または「reinterpret_cast <」は簡単に検索できます。
pOther = reinterpret_cast<CMyOtherStuff*>(pSomething);
// No compiler error.
// but the presence of a reinterpret_cast<> is
// like a Siren with Red Flashing Lights in your code.
// The mere typing of it should cause you to feel VERY uncomfortable.
つまり、Cスタイルのキャストの方が危険であるだけでなく、すべてを見つけて正しいことを確認するのが非常に困難です。
static_cast
継承階層のキャストダウンには使用しないでくださいdynamic_cast
。これは、nullポインターまたは有効なポインターを返します。
static_cast
そのような状況で使用する際の注意点を示したと思います。dynamic_cast
安全かもしれませんが、それが常に最良の選択肢であるとは限りません。時々あなたは知っていますポインターがコンパイラーに対して不透明であることにより、特定のサブタイプを指しているているあり、aの方static_cast
が高速です。少なくとも一部の環境でdynamic_cast
は、オプションのコンパイラサポートとランタイムコスト(RTTIを有効にする)が必要であり、自分で実行できるいくつかのチェックのためだけに有効にしたくない場合があります。C ++のRTTIは、この問題に対する唯一の可能な解決策です。
static_cast
。Cと同等のreinterpret_cast
isは*(destination_type *)&
、つまり、オブジェクトのアドレスを取得し、そのアドレスを別の型へのポインターにキャストしてから、逆参照します。Cは、この構築物の挙動を定義するための文字タイプまたは特定の構造体タイプの場合を除き、それは一般的にCの未定義の動作につながる
int
(およびint
単独)の場合、なぜ使用するのかstatic_cast<int>
vs。(int)
を、クラス変数とポインターをすることだけにあるようです。これについて詳しく説明してください。
int
dynamic_cast
適用されませんが、他のすべての理由が立っています。たとえば:みましょうと言うには、v
関数のパラメータは、として宣言されfloat
、その後、(int)v
ですstatic_cast<int>(v)
。あなたがにパラメータを変更した場合でもfloat*
、(int)v
静かになりreinterpret_cast<int>(v)
ながら、static_cast<int>(v)
違法であり、正しくコンパイラによってキャッチ。
実用的なヒントの1つ:プロジェクトを片付ける場合は、ソースコードでstatic_castキーワードを簡単に検索できます。
int
パラメーターを持つ関数宣言。
つまり:
static_cast<>()
コンパイル時間チェック機能を提供しますが、C-Styleキャストは提供しません。static_cast<>()
C ++ソースコード内のどこにでも簡単に見つけることができます。対照的に、C_Styleキャストは見つけにくいです。- C ++キャストを使用すると、意図がより適切に伝えられます。
詳細な説明:
静的キャストは、互換性のある型間の変換を実行します。Cスタイルのキャストに似ていますが、より制限的です。たとえば、Cスタイルのキャストでは、整数ポインターがcharを指すことができます。
char c = 10; // 1 byte int *p = (int*)&c; // 4 bytes
これにより、割り当てられたメモリの1バイトを指す4バイトのポインタが生成されるため、このポインタに書き込むと、ランタイムエラーが発生するか、隣接するメモリの一部が上書きされます。
*p = 5; // run-time error: stack corruption
Cスタイルのキャストとは対照的に、静的キャストを使用すると、コンパイラーはポインターと指示先のデータ型に互換性があることを確認できるため、プログラマーはコンパイル中にこの誤ったポインター割り当てをキャッチできます。
int *q = static_cast<int*>(&c); // compile-time error
続きを読む:
static_cast <>とCスタイルのキャスト
、通常のキャストとstatic_castとdynamic_cast の違いは何ですか
static_cast<>()
もっと読みやすいとは思いません。つまり、時々そうですが、ほとんどの場合、特に基本的な整数型では、それは恐ろしく、不必要に冗長です。例:これは、32ビットワードのバイトをスワップする関数です。static_cast<uint##>()
キャストを使用して読むことはほとんど不可能ですが、(uint##)
キャストを使用して理解することは非常に簡単です。コードの画像: imgur.com/NoHbGve
always
でも私はどちらも言わなかった。(しかし、ほとんどの場合はそうです)cスタイルのキャストの方がずっと読みやすい場合があります。それが、cスタイルのキャストがまだライブでc ++ imhoを開始している理由の1つです。:)ちなみに、それはとても良い例でした
(uint32_t)(uint8_t)
)を使用して、最下位以外のバイトがリセットされるようにします。そのため、ビットごとの(0xFF &
)があります。キャストの使用は意図を難読化しています。
Cスタイルのキャストを使用するとさまざまなことが起こるため、静的なキャストやCスタイルのキャストを単に使用するよりも問題が大きくなります。C ++キャスト演算子は、これらの操作をより明示的にすることを目的としています。
一例として、static_castとCスタイルのキャストは同じように見えます。たとえば、ある値を別の値にキャストする場合です。
int i;
double d = (double)i; //C-style cast
double d2 = static_cast<double>( i ); //C++ cast
これらは両方とも整数値をdoubleにキャストします。ただし、ポインタを操作する場合、状況はさらに複雑になります。いくつかの例:
class A {};
class B : public A {};
A* a = new B;
B* b = (B*)a; //(1) what is this supposed to do?
char* c = (char*)new int( 5 ); //(2) that weird?
char* c1 = static_cast<char*>( new int( 5 ) ); //(3) compile time error
この例では、(1)Aが指すオブジェクトは実際にはBのインスタンスなので、おそらくOKです。しかし、コードのその時点で実際に指しているものがわからない場合はどうでしょうか。(2)おそらく完全に合法です(整数の1バイトのみを確認する必要があります)が、(3)のようにエラーが発生した場合にエラーになることもあります。C ++キャスト演算子は、可能な場合にコンパイル時エラーまたは実行時エラーを提供することにより、コードでこれらの問題を公開することを目的としています。
したがって、厳密な「値のキャスト」には、static_castを使用できます。実行時にポインタのポリモーフィックキャストが必要な場合は、dynamic_castを使用します。タイプを忘れたい場合は、reintrepret_castを使用できます。そして、単にconstをウィンドウから投げ出すためにconst_castがあります。
彼らはあなたが何をしていたかあなたが知っているように見えるように、コードをより明確にするだけです。
効果的なC ++の概要を参照してください
それはあなたが課したいどれだけのタイプセーフについてです。
あなたが書くとき(bar) foo
(これはreinterpret_cast<bar> foo
、型変換演算子を指定していない場合と同じです)、型の安全性を無視するようコンパイラーに指示し、指示されたとおりに実行します。
あなたが書くとき static_cast<bar> foo
、少なくとも型変換が意味があることを確認し、整数型の場合は変換コードを挿入するようコンパイラーに要求します。
編集2014-02-26
私は5年以上前にこの回答を書きましたが、間違っていました。(コメントを参照してください。)しかし、それでも賛成票が入ります!
static_cast<bar>(foo)
括弧付きです。も同じですreinterpret_cast<bar>(foo)
。
Cスタイルのキャストは、コードのブロックで見逃しがちです。C ++スタイルのキャストは、優れた実践方法であるだけではありません。はるかに高い柔軟性を提供します。
reinterpret_castは、ポインター型変換への統合を許可しますが、誤用すると危険な場合があります。
static_castは、数値型(enumからintやintからfloatへの変換、または型に自信のある任意のデータ型)を適切に変換します。ランタイムチェックは実行されません。
一方、dynamic_castは、これらのチェックを実行して、あいまいな割り当てまたは変換にフラグを立てます。ポインタと参照でのみ機能し、オーバーヘッドが発生します。
他にもいくつかありますが、これらはあなたが遭遇する主なものです。
static_castは、クラスへのポインタの操作の他に、クラスで明示的に定義された変換を実行したり、基本的な型間の標準変換を実行したりするためにも使用できます。
double d = 3.14159265;
int i = static_cast<int>(d);
static_cast<int>(d)
しかし、なぜ(int)d
もっと簡潔で読みやすいのに、誰もがと書くのでしょうか?(つまり、オブジェクトポインターではなく、基本型の場合です。)
(int)d
時には、int{d}
以前よりもずっと読みやすいのですか?コンストラクター、またはのように関数のように()
、構文は、複雑な式の括弧の悪夢のような迷路に展開するのにそれほど高速ではありません。この場合、のint i{d}
代わりになりint i = (int)d
ます。はるかに優れたIMO。とは言っても、式で一時的なものだけが必要な場合は、static_cast
コンストラクタキャストを使用したことがないので、考えていません。私は(C)casts
急いでデバッグcout
s ...を作成するときにのみ使用します