変数を初期化することの重要性


9

変数を初期化することはどのくらい重要ですか?

適切に初期化することでメモリリークを回避できますか、それともパフォーマンス上の利点がありますか


14
言語によって異なります。一部の言語では、バグを防ぐことが非常に重要ですが、残りの言語では、読みやすさを向上させるために行うことは単に良いことです。
Telastyn 2014年

Telastynにご協力いただきありがとうございます。言語によっては重要になるケースはありますか?
Vivek 2014年

4
C ++はここで悪名高いものです。デバッグでは、ローカル変数はnull一般的なコンパイラによって0(または)に初期化されますが、リリース用にコンパイルするとランダムなガベージになります。(私のC ++の知識は約10年前のものですが、状況は変わった可能性があります)
Telastyn

二度恥ずかしがり屋の場合です。初期化されていない変数、特にポインタによって引き起こされるバグを見た/持っていたので、それは習慣になっています。パフォーマンスに関しては、通常は関係ありません。メモリリークの場合、問題はありません。
Mike Dunlavey、2014

1
@Telastynそれよりも悪い。未定義の動作はガベージ状態に限定されず、何が起こってもかまいません。コンパイラーは、初期化されていない変数を読み取るパスは到達不能であると想定し、途中で発生する「無関係な」影響を排除できます。
Caleth

回答:


7

初期化されていない変数は、プログラムを非決定性にします。プログラムが実行されるたびに、動作が異なる場合があります。動作環境、時刻、月の位相、およびそれらの順列への無関係な変更は、これらのデーモンがいつどのように出現するかに影響します。プログラムは、欠陥が発生する前に100万回実行される場合もあれば、毎回実行される場合もあれば、100万回実行される場合もあります。多くの問題は「不具合」に分類されて無視されるか、顧客からの欠陥レポートが「再現不能」としてクローズされました。問題を「修正」するためにマシンをどのくらいの頻度で再起動しましたか?どのくらいの頻度でお客様に「それが起こったことは一度も見たことがないので、もう一度見た場合はお知らせください」と言ったことはありませんか。

欠陥の再現はテスト環境ではほとんど不可能であるため、発見して修正することはほぼ不可能です。

一般に、信頼性が高く安定していると考えられるコードでは、バグが表面化するまでに数年かかる場合があります。欠陥はより最近のコードにあると推定されます-それを追跡するのにかなり長い時間がかかる場合があります。コンパイラの変更、コンパイラスイッチ、さらにはコード行を追加するだけでも、動作が変わる可能性があります。

変数を初期化することは、正しく機能するプログラムがそうでないプログラムよりも無限に速いというだけでなく、開発者がそこにあるはずのない欠陥を見つけて修正するのに費やす時間を減らし、「実際の」作業を行う時間を増やすという、大きなパフォーマンス上の利点があります。

変数を初期化する他の重要な利点は、コードの元の作成者が初期化する対象を決定する必要があることです。これは常に些細なことではなく、些細なことではない場合は、設計が悪いことを示している可能性があります。

メモリリークは別の問題ですが、適切な初期化はそれらを防ぐのに役立つだけでなく、それらを検出してソースを見つけるのにも役立ちます-これは非常に言語に依存します。この答えで。

編集:一部の言語(C#など)では、初期化されていない変数を使用することはできません。プログラムがコンパイルされなかったり、実行時にエラーが報告されたりするためです。ただし、これらの特性を持つ多くの言語には潜在的に安全でないコードへのインターフェースがあるため、そのようなインターフェースを使用する場合は、初期化されていない変数を導入しないように注意する必要があります。


6
多くのプログラミング言語は自動的に変数をいくつかの事前定義された値に設定するため、ここで言うことの多くはそれらの言語には適用されません。
Robert Harvey、

2
@RobertHarveyの発言を繰り返すと、これはC#には適用されません。変数を宣言するときに変数を初期化してもパフォーマンス上の利点はありません。また、初期化されていない変数を使用することは不可能であるため、再現できないバグのせいにすることはできません。(初期化されていないクラスフィールドを使用すること可能ですが、デフォルト値に設定され、その場合警告が生成されます)
Bobson

4
@mattnz-ポイントは、C#(またはJava)のように動作する言語の場合、このアドバイスの一部は誤解を招く、またはまったく間違っているということです。言語にとらわれない質問として、言語にとらわれない応答が必要です。つまり、初期化された変数を安全に処理する言語とそうない言語をアドレス指定することを意味します。
ボブソン2014年

1
私はまた、初期化されていない変数の問題は、それらについて警告する任意の半分のまともなコンパイラ/静的アナライザとして見つけることは困難ではありません追加したい
JKを。

1
Java(およびおそらくC#)の場合、ローカルを時期尚早に初期化する必要はなく、おそらくより多くのバグにつながります。たとえば、変数を条件付きで割り当てる前にnullに設定すると、コードのパスの1つで変数が割り当てられない可能性があることをコンパイラが判断できなくなります。
JimmyJames、

7

Telastynが指摘したように変数を初期化すると、バグを防ぐことができます。変数が参照型の場合、変数を初期化することで、後のnull参照エラーを防ぐことができます。

null以外のデフォルトを持つ任意の型の変数は、デフォルト値を格納するためにメモリを消費します。


6

初期化されていない変数を使用しようとすることは常にバグであるため、そのバグが発生する可能性を最小限に抑えることは理にかなっています。

おそらく、問題を緩和するためにプログラミング言語が取る最も一般的なアプローチは、自動的にデフォルト値に初期化することです。そのため、少なくとも変数を初期化し忘れた場合は、のようなものでは0なく、のようなものになり0x16615c4bます。

とにかくゼロに初期化された変数が必要になった場合、これはバグの大部分を解決します。ただし、誤った値に初期化された変数を使用することは、まったく初期化されなかった変数を使用するのと同じくらい悪いことです。実際、エラーはより微妙で検出が困難な場合があるため、さらに悪化する場合もあります。

関数型プログラミング言語は、初期化されていない値を許可しないだけでなく、再割り当てを完全に禁止することによってこの問題を解決します。これで問題が解消され、思ったほど制限が厳しくないことがわかります。非関数型言語であっても、初期化する正しい値が得られるまで変数を宣言するのを待つと、コードははるかに堅牢になる傾向があります。

パフォーマンスに関する限り、それはおそらくごくわずかです。最悪の場合、初期化されていない変数では、割り当てが1つ増え、必要以上に長くメモリを占有します。優れたコンパイラは、多くの場合、違いを最適化できます。

メモリリークは完全に無関係ですが、適切に初期化された変数はより短い期間スコープに入る傾向があるため、プログラマーが誤ってリークする可能性は少し低くなります。


常に?「修正されたValgrindメッセージがOpenSSLを次のように無効にする方法」のように「常に」marc.info/?t=114651088900003&r=1&w=2?それとも、「ほぼ常に」という他の意味ですか?
JensG 2014年

1
初期化されていない変数をエラーなしで許可する3つの言語を考えることができます。そのうちの1つは、言語の目的でそのようなものを使用します。
DougM 2014年

詳細に興味があります。これらの場合、変数は本当に初期化されていないのではないかと思いますが、宣言サイトのプログラマーが直接行う以外の方法で初期化されています。または、間接参照される前に、間接的な方法で割り当てられます。
カールビーレフェルト

5

初期化は、初期値が重要であることを意味します。初期値が重要な場合は、はい、明らかに、初期化されていることを確認する必要があります。それが問題ではない場合、それは後で初期化されることを意味します。

不要な初期化により、CPUサイクルが浪費されます。これらの無駄なサイクルは特定のプログラムでは問題にならない可能性がありますが、他のプログラムでは、速度が主な関心事であるため、すべての単一サイクルが重要です。したがって、パフォーマンスの目標を理解し、変数を初期化する必要があるかどうかを理解することが非常に重要です。

メモリリークは完全に異なる問題であり、通常はメモリアロケータ関数がメモリブロックを発行して後でリサイクルする必要があります。郵便局を考えてみてください。あなたは行って郵便受けを求めます。彼らはあなたに1つを与えます。あなたは別のものを求めます。彼らはあなたに別のものを与えます。ルールは、あなたがそれを返す必要があるメールボックスを使い終わったときであるということです。あなたがそれを返すのを忘れた場合、彼らはまだあなたがそれを持っていると考え、箱は他の人が再利用することはできません。そのため、使用されていないメモリのチャンクが拘束されており、これがメモリリークと呼ばれています。ある時点でボックスを要求し続けると、メモリが不足します。これを単純化しすぎましたが、これが基本的な考え方です。


-1これは、このコンテキストでの初期化の意味を再定義しています。
ピーターB

@ピーターB、コメントがわかりません。もし私がどういうことか、「この文脈での初期化の意味を再定義する」と言ったら、どうぞ。ありがとう
楕円形のビュー

あなた自身の文を読んでください、それは循環的な推論です:「初期化することは初期値が重要であることを意味します。初期値が重要な場合は、はい、明らかに、それが初期化されていることを確認する必要があります。重要でない場合、それは後で初期化されました。」
Pieter B

@Pieter B、プログラム上の理由ではなく、一般的な規則として初期化する人もいます。つまり、初期値が重要かどうかに関係なく初期化します。これがOQの中心ではありません。変数を初期化することはどれほど重要ですか。とにかく、あなたはここで投票されていません。
楕円形のビュー

2

他の人が言ったように、それは言語に依存します。ただし、変数の初期化に関するJava(および効果的なJava)のアイデアを示します。これらは、他の多くの高水準言語で使用できるはずです。

定数とクラス変数

staticJavaでマークされたクラス変数は定数のようなものです。これらの変数は通常、最終であり=、クラス初期化子ブロックを使用して、またはクラス初期化子ブロック内から定義した直後に初期化する必要がありますstatic { // initialize here }

田畑

多くの上位レベルおよびスクリプト言語と同様に、フィールドには自動的にデフォルト値が割り当てられます。数値の場合、charこれはゼロ値になります。文字列およびその他のオブジェクトの場合は、になりますnull。今nullは危険なので、控えめに使用する必要があります。したがって、これらのフィールドはできるだけ早く有効な値に設定する必要があります。通常、コンストラクターはこれに最適な場所です。変数がコンストラクターの間に設定され、後で変更されないことを確認するために、finalキーワードでそれらをマークすることができます。

nullある種の旗や特別な価値として使用したいという衝動に抵抗してください。たとえば、状態を保持する特定のフィールドを含めることをお勧めします。列挙型stateの値を使用する名前のフィールドがState適切な選択です。

メソッドパラメータ

パラメータの値に対する変更(オブジェクトまたは整数などの基本的な型への参照)は呼び出し元からは認識されないため、パラメータはとしてマークする必要がありますfinal。つまり、変数自体の値は変更できません。変更可能なオブジェクトインスタンスの値は変更できますが、参照を変更して別のオブジェクトをポイントすることはできませんnull

ローカル変数

ローカル変数は自動的に初期化されません。値を使用する前に初期化する必要があります。変数が確実に初期化されるようにする1つの方法は、変数をある種のデフォルト値に直接初期化することです。ただし、これは行うべきではありません。ほとんどの場合、デフォルト値は期待した値ではありません。

変数を必要な場所にのみ正確に定義する方がはるかに優れています。変数が単一の値のみを取る場合(これは、適切なコードのほとんどの変数に当てはまります)、変数にマークを付けることができますfinal。これにより、ローカル変数が0回または2回ではなく、正確に1回割り当てられることが保証されます。例:

public static doMethod(final int x) {
    final int y; // no assignment yet, it's final so it *must* be assigned
    if (x < 0) {
        y = 0;
    } else if (x > 0) {
        y = x;
    } else {
        // do nothing <- error, y not assigned if x = 0
        // throwing an exception here is acceptable though
    }
}

変数が使用前に初期化されていない場合、多くの言語で警告が表示されることに注意してください。言語仕様とフォーラムをチェックして、不必要に心配しないかどうかを確認してください。


1

変数の初期化を解除しても問題はありません。

問題は、まだ書き込まれていない変数を読み取るときだけです。

コンパイラーや変数の種類によっては、アプリケーションの起動時に初期化が実行されます。か否か。

自動初期化に依存しないのが一般的な使用法です。


0

変数の初期化(暗黙的または明示的)は重要です。変数を初期化しないと、常にエラーになります(ただし、暗黙的に初期化される場合があります。以下を参照してください)。C#コンパイラなどの最新のコンパイラは(例として)、これをエラーとして扱い、コードを実行させません。初期化されていない変数は、単に役に立たず、有害です。乱数ジェネレータを作成しているのでない限り、コードの一部から確定的で再現可能な結果が生成されることが期待されます。これは、初期化された変数の操作を開始した場合にのみ達成できます。

本当に興味深い質問は、変数が自動的に初期化されるのか、それとも手動で行う必要があるのか​​ということです。使用する言語によって異なります。たとえばC#では、クラスレベルの「変数」などのフィールドは、常にその変数の型のデフォルト値に自動的に初期化されますdefault(T)。この値は、すべてゼロで構成されるビットパターンに対応します。これは言語仕様の一部であり、言語の実装の技術的な詳細だけではありません。したがって、安全に信頼できます。言語仕様で暗黙的に初期化されていると宣言されている場合に限り、変数を明示的に初期化しない方が安全です。別の値が必要な場合は、変数を明示的に初期化する必要があります。しかしながら; C#では、ローカル変数、つまりメソッドで宣言された変数は自動的に初期化されないため、常に変数を明示的に初期化する必要があります。


2
これはC#固有の質問ではありません。
DougM 2014年

@DougM:わかっています。これはC#固有の答えではありません。例としてC#を取り上げました。
Olivier Jacot-Descombes 2014年

すべての言語で変数を明示的に初期化する必要があるわけではありません。あなたの「初期化しないことは常にエラーである」という記述は誤りであり、目の前の質問に明確さを加えません。あなたはあなたの答えを修正したいかもしれません。
DougM 2014年

@DougM:「本当に興味深い質問は、変数が自動的に初期化されるのか、それとも手動で初期化する必要があるのか​​」という私の文章を監督したことがありますか?
Olivier Jacot-Descombes 2014年

段落の途中で埋められたものですか?はい。あなたはそれをもっと目立つようにし、あなたの「常に」の主張に修飾子を加えるべきだった。
DougM 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.