[解決済み] ループ内での変数宣言、グッドプラクティスかバッドプラクティスか?
質問
質問1: ループの中で変数を宣言することはグッドプラクティスですか、バッドプラクティスですか?
他のスレッドで、パフォーマンスの問題があるかどうか(ほとんどの人がノーと言っています)、変数は常に使用される場所の近くで宣言するべきだという話を読みました。私が疑問に思っているのは、これを避けるべきか、あるいは実際に好ましいかということです。
例
for(int counter = 0; counter <= 10; counter++)
{
string someString = "testing";
cout << someString;
}
質問その2です。 ほとんどのコンパイラは、変数がすでに宣言されていることを認識して、その部分をスキップするのでしょうか、それとも実際に毎回メモリ内にその変数のためのスポットを作成するのでしょうか?
解決方法は?
これは エクセレント を実践しています。
ループの中に変数を作成することで、そのスコープがループの中に限定されることを保証します。ループの外から参照したり、呼び出したりすることはできません。
このように
-
変数名が少し一般的なもの("i"など)であれば、コード内のどこかで同名の別の変数と混在するリスクはありません(quot;i"を使用して軽減することもできます)。
-Wshadow
GCCの警告命令) -
コンパイラは変数のスコープがループ内に限定されていることを認識しているので、誤って他の場所を参照した場合、適切なエラーメッセージを発行します。
-
最後になりましたが、コンパイラはループの外では変数を使用できないことを知っているので、いくつかの専用の最適化(最も重要なのはレジスタの割り当て)をより効率的に実行することができるのです。例えば、後で再利用するために結果を保存する必要がありません。
要するに、やって正解なんです。
ただし、変数が その値を保持することは想定されていません。 ループのたびに そのような場合は、毎回初期化する必要があるかもしれません。また、ループを包含する大きなブロックを作成し、ループ間で値を保持しなければならない変数を宣言することだけを目的とすることもできます。このブロックには、通常、ループカウンタが含まれます。
{
int i, retainValue;
for (i=0; i<N; i++)
{
int tmpValue;
/* tmpValue is uninitialized */
/* retainValue still has its previous value from previous loop */
/* Do some stuff here */
}
/* Here, retainValue is still valid; tmpValue no longer */
}
質問2について。 変数は、関数が呼び出されたときに一度だけ割り当てられます。実際、割り当ての観点からは、関数の先頭で変数を宣言するのと(ほぼ)同じです。唯一の違いはスコープで、変数はループの外では使用できません。この変数はループの外では使用できません。また、変数が割り当てられるのではなく、(スコープが終了した他の変数の)空きスロットを再利用するだけということもありえます。
スコープを制限し、より正確にすることで、より正確な最適化が可能になります。しかし、より重要なのは、コードの他の部分を読むときに心配する状態(つまり変数)が少なくなり、コードがより安全になることです。
このことは
if(){...}
ブロックを作成します。通常、:
int result;
(...)
result = f1();
if (result) then { (...) }
(...)
result = f2();
if (result) then { (...) }
と書いた方が無難です。
(...)
{
int const result = f1();
if (result) then { (...) }
}
(...)
{
int const result = f2();
if (result) then { (...) }
}
この違いは、特にこのような小さな例では、些細なことに思えるかもしれません。
しかし、より大きなコードベースでは、これは役に立つでしょう。
result
の値を
f1()
から
f2()
ブロックを作成します。それぞれの
result
は厳密に自分の範囲に限定されるため、その役割がより正確になります。レビュアーの立場からすると、彼の持つ
長距離状態変数
を心配し、追跡する必要があります。
コンパイラーも、より良い手助けをしてくれるでしょう : 将来、誤ってコードを変更した後を想定して。
result
で適切に初期化されない場合
f2()
. 2番目のバージョンは単純に動作を拒否し、コンパイル時に明確なエラーメッセージを表示します(実行時よりもずっと良い方法です)。最初のバージョンは何も表示されません。
f1()
の結果と混同して、2回目のテストが行われるだけです。
f2()
.
補足情報
オープンソースツール CppCheck (C/C++コードの静的解析ツール)は、変数の最適なスコープについて、いくつかの優れたヒントを提供しています。
アロケーションに関するコメントに対して。 上記のルールはC言語では正しいのですが、C++のクラスによってはそうではないかもしれません。
標準的な型や構造体では、変数のサイズはコンパイル時に分かっています。C言語には「構築」という概念がないため、関数が呼び出されると、変数の領域が(初期化なしで)単純にスタックに確保されます。そのため、ループ内で変数を宣言した場合のコストはゼロになります。
しかし、C++のクラスでは、コンストラクタというものがあり、私はあまりよく知りません。コンパイラは同じスペースを再利用するほど賢いので、おそらくアロケーションは問題にならないだろうが、初期化はループの反復ごとに行われる可能性が高い。
関連
-
[解決済み】Cygwin Make bash コマンドが見つかりません。
-
[解決済み】関数名の前に期待されるイニシャライザー
-
[解決済み】fpermissiveフラグは何をするのですか?
-
[解決済み】エラー:strcpyがこのスコープで宣言されていない
-
[解決済み】エラー:free(): 次のサイズが無効です(fast)。
-
[解決済み】CMakeエラー at CMakeLists.txt:30 (project)。CMAKE_C_COMPILER が見つかりませんでした。
-
[解決済み】1つ以上の多重定義されたシンボルが見つかる
-
[解決済み] ループ内のJavaScriptクロージャ - シンプルな実用例
-
[解決済み] using namespace std;」はなぜバッドプラクティスだと言われるのですか?
-
[解決済み] ループの前に変数を宣言するのか、ループの中で宣言するのかの違い?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】 unsigned int vs. size_t
-
[解決済み】C++でint型に無限大を設定する
-
[解決済み】Visual Studio 2015で「非標準の構文。'&'を使用してメンバーへのポインターを作成します」エラー
-
[解決済み】C++でユーザー入力を待つ【重複あり
-
[解決済み】エラー:strcpyがこのスコープで宣言されていない
-
[解決済み】「std::operator」で「operator<<」にマッチするものがない。
-
[解決済み】ファイルから整数を読み込んで配列に格納する C++ 【クローズド
-
[解決済み] 配列のベクトルを扱う正しい方法
-
[解決済み] ループの前に変数を宣言するのか、ループの中で宣言するのかの違い?
-
[解決済み] ループ内で変数を宣言することにオーバーヘッドはあるのか?(C++)