賛否両論:条件文で変数を初期化する
-
02-07-2019 - |
質問
C ++では、ifステートメントの変数を次のように初期化できます。
if (CThing* pThing = GetThing())
{
}
この悪いスタイルや良いスタイルを考えるのはなぜですか?利点と欠点は何ですか?
個人的にこのスタイルが好きなのは、pThing変数のスコープを制限するためです。そのため、NULLの場合に誤って使用されることはありません。ただし、これができないのは気に入らない:
if (CThing* pThing = GetThing() && pThing->IsReallySomeThing())
{
}
上記の作業を行う方法がある場合は、投稿してください。しかし、それが不可能な場合でも、理由を知りたいです。
解決
重要なことは、C ++の宣言は式ではないことです。
bool a = (CThing* pThing = GetThing()); // not legit!!
ifステートメントで宣言とブールロジックの両方を行うことはできません。C++言語仕様では、式または宣言のいずれかのみが明確に許可されています。
if(A *a = new A)
{
// this is legit and a is scoped here
}
式内でaが1つの用語と別の用語の間に定義されているかどうかを知るにはどうすればよいですか?
if((A *a = new A) && a->test())
{
// was a really declared before a->test?
}
箇条書きをかみ、内部ifを使用します。スコープルールは有用であり、ロジックは明示的です:
if (CThing* pThing = GetThing())
{
if(pThing->IsReallySomeThing())
{
}
}
他のヒント
利点について:
変数は、1行前ではなく、最初に必要なときに常に定義することをお勧めします。これは、スクロールして定義された場所を検索することなくCThingが何であるかを知ることができるため、コードの可読性を向上させるためです。
ループ/ ifブロックにスコープを縮小すると、コードブロックの実行後に変数が参照されなくなり、ガーベッジコレクションの候補になります(言語がこの機能をサポートしている場合)。
if (CThing* pThing = GetThing())
if
内ではブール式を提供していないため、悪いスタイルです。 CThing *
を提供しています。
CThing* pThing = GetThing();
if (pThing != NULL)
これは良いスタイルです。
私が通常そうしない理由の1つは、条件付きテストで「=」を見逃したことによる一般的なバグのためです。エラー/警告を設定してlintを使用し、それらをキャッチします。その後、条件内のすべての割り当てについて叫びます。
参考までに、一部の古いMicrosoft C ++コンパイラ(Visual Studios 6、および.NET 2003と思われる)のいくつかは、場合によってはスコーピングルールに従っていないことがあります。
for(int i = 0; i > 20; i++) {
// some code
}
cout << i << endl;
私は範囲外にすべきですが、それは有効なコードでした。私はそれが機能としてプレイされたと信じていますが、私の意見ではそれはただの非準拠です。標準に準拠しないことは悪いことです。 IEとFirefoxに関するWeb開発者と同じように。
VSを持っている人がそれがまだ有効かどうかを確認して確認できますか?
この は、短絡評価。 多分以下を試さないでください:
if ((CThing* pThing = GetThing()) && (pThing->IsReallySomeThing()))
{
}
err .. Wesley Tarleの回答
警告メッセージを防ぐために、割り当てを追加のセット()で囲むこともできます。
それは一種の危険だと思います。以下のコードの方がはるかに安全であり、中括弧で囲むと、pThingのスコープが希望どおりに制限されます。
GetThing()がNULLを返す場合があるため、if()ステートメントにその面白い句を入れています。 NULLポインターでIsReallySomething()が呼び出されるのを防ぎます。
{
CThing *pThing = GetThing();
if(pThing ? pThing->IsReallySomeThing() : false)
{
// Do whatever
}
}
また、C ++コードを記述している場合、コンパイラに&quot; =&quot;について警告するようにしたいことにも注意してください。条件文(宣言の一部ではない)のエラー。
それは受け入れられ、良いコーディングの習慣です。ただし、低レベルのコーディングのバックグラウンドから来ていない人は、おそらく同意しないでしょう。
非常に多くのこと。まず、裸のポインター。絶対に避けてください。参照、オプション、unique_ptr、shared_ptrを使用します。最後の手段として、ポインターの所有権のみを扱う独自のクラスを作成します。
C ++ 11が必要な場合は、均一な初期化を使用します(C ++ 11の欠陥を回避するためにC ++ 14を推奨):-= vs ==の混乱を回避し、引数がある場合はより厳密にチェックします。
if (CThing thing {})
{
}
必ず operator bool
を実装して、CThingからboolへの予測可能な変換を取得してください。ただし、コードを読んでいる他の人には、 operator bool
はすぐには表示されないことに注意してください。一般に、明示的なメソッド呼び出しは読みやすく、安心できます。 C ++ 17が必要な場合は、初期化構文を使用します。
if (CThing thing {}; thing.is_good())
{
}
C ++ 17がオプションではない場合、他の人が示唆している場合は上記の宣言を使用してください。
{
CThing thing {};
if (thing.is_good())
{
}
}