高品質コードの作成-C++プログラムを改善する150の提案-4

4519 ワード

最近、図書館から「高品質コードの作成-C++プログラムの改善に関する150の提案」という本を借りました.いい感じで、内容を抜粋して、自分の勉強の点滴を記録します.みんなと分かち合うのも好きです.
また、ハイビジョンpdfも見つかりました.私のリソースにアップロードされました.  
次はダウンロードリンクです.時にダウンロードページに入ります.
皆さんが読んでから自分の学習経験を分かち合うことを歓迎します.
提案3:式の計算順序を当たり前に考えない
1本1本の式がC/C++コードの主体を構成している.次に、式の計算順序についてお話しします.これらは些細なことだが、否定できないのは非常に価値がある.次のコードクリップはよく知られていると思います.
if( nGrade & MASK == GRADE_ONE )  
    ... // processing codes

gradeがGRADEに等しい場合ONE時if条件が成立するのがプログラマーの本意です.しかし、上のコードはプログラマーの意味を正しく表現していません.これは、ビット演算子(&および|)の優先度がリレーショナル演算子(==、<、>)より低いため、上記のコードの実際の効果は次のとおりです.
if( nGrade & (MASK == GRADE_ONE) )  
    ... // processing codes

これは多くの人が犯しやすい間違いで、私も似たような経験があります.もちろんプログラムは想定の順序で実行されると思います.このようなエラーは発見しにくく、デバッグもかなり骨が折れる.C++/C言語の演算子は数十個に達し、この数十個の演算子はまた異なる優先度と結合律を持っており、それらを熟知するのは確かに難しいが、カッコで意図をより明確に表すことができるので、カッコを惜しんで使用しないでください.
if( (nGrade & MASK) == GRADE_ONE )  
    ... // processing codes

これにより、コードに曖昧さはなくなります.
C/C++言語には「かなり危険」な優先順位の問題があり、多くの人が間違いを犯しやすい.コード式に多くの演算子が含まれている場合、曖昧さを防止し、可読性を向上させるために、式の各サブ式の計算順序をカッコで決定することができ、すべての演算子の優先度、結合律を熟知していると自信を持って考えすぎないで、カッコをいくつか書くのは確かに良いアイデアです.例:
COLOR rgb = (red<<16) | (green<<8) | blue;  
bool isGradeOne = ((nGrade & MASK) == GRADE_ONE);

上記の計算順序は、演算子の優先順位であり、「前菜」にすぎません.次に、最も奇妙な式が評価の順序を評価する問題について説明します.
C++とC言語の間の「剪断が絶えず理が乱れている」という特殊な関係のため、C言語の多くの問題もC++の世界に持ち込まれ、式評価の評価順序の問題も含まれている.C言語の誕生当初、プロセッサレジスタは異常に貴重な資源であった.複雑な式はレジスタに対する要求が高く、コンパイラは大きな圧力を受けている.コンパイラに高度に最適化された実行可能コードを生成させるために、C言語の創造者たちはレジスタディスペンサにこのような追加の能力を与え、式が評価をどのように評価するかという問題に大きな処理の余地を残した.現在、レジスタは大きく進歩しており、複雑な式の評価には圧力はありませんが、レジスタ割り当て器に与えられたこの能力は回収されていません.そのため、C++で評価された評価順序の不確実性は依然として存在し、使用するコンパイラに決定されています.これは、表現に根拠のない先入観的な評価順序が設定されないように、ソフトウェアエンジニアがより真剣に注意することを要求しています.
これも実はC言語の罠の一つで、『The C Programming Lauguage』(プログラマーが親切にこの本を「K&R」と呼ぶ)では、関数パラメータにしても、あるオペレータの操作数にしても、式の評価順序は一定ではなく、特定の機器、オペレーティングシステム、コンパイラごとに異なることを繰り返し強調している.『The C Programming Language』影印版第2版の52ページで述べたように、
ほとんどの言語と同様に、C言語もオペレータのどのオペランドが先に計算されたかを識別することはできません(&&,|,?:および、4つのオペレータを除く).例えばx=f()+g()です.
ここでいう評価順序は主に以下の2つの側面を含む.
関数パラメータの評価評価順序
次のコードクリップの出力結果を分析します.
int i = 2010;  
printf("The results are: %d %d", i, i+=1 );

関数パラメータの評価評価評価は一定の順序がないためprintf()関数の出力結果は2010,2011,2011である可能性があり,2011,2011である可能性がある.
似たようなものは次のとおりです.
printf("The results are: %d %d", p(), q() );

p()とq()はいったい誰が先に呼び出されたのか,コンパイラだけが知っている問題である.
この問題を回避するために、経験のあるエンジニアは、パラメータテーブルに1回以上現れた変数が、伝達時にその値を変更しないことを保証します.それでも万全ではありません.十分な注意がなければ、誤った引用は次のように努力を放棄します.
int para = 10;  
int &rPara = para;  
int f(int, int);  
int result = f(para, rPara *= 2);

推奨される形式は次のとおりです.
int i = 2010;  
printf("The results are: %d %d", i, i+1 );  
 
int ppara = p();  
printf("The results are: %d %d", para, q() );  
 
int para = 10;  
int f(int, int);  
int result = f(para, para*2);

オペランドの評価評価順序
オペランドの評価評価評価順序も固定されていません.次のコードに示します.
a = p() + q() * r();

3つの関数p()、q()およびr()は、6つの順序のいずれかで評価され得る.乗算演算子の高優先度は、q()とr()の戻り値が最初に乗算され、p()の戻り値に加算されることを保証するしかない.だから、いくらカッコをつけても問題は解決できません.
幸いなことに、明示的で手作業で指定された中間変数を使用すると、この問題を解決することができ、固定されたサブエクスプレッションが評価の順序を評価することを保証します.
int ppara1 = p();  
int para2 = q();  
a = para1 + para2 * r();

このように,上記コードはp(),q(),r()の3つの関数に対して,p()→q()→r()の一意の計算順序を指定する.
また,誕生日から明確なオペランド評価順序を持つ演算子もあり,独特の信頼性を持っている.たとえば、次の式があります.
(a < b) && (c < d)

C/C++言語では、a三次条件演算子:パラメータの評価評価評価順序を固定する役割も果たしています.
expr1 ? expr2 : expr3

最初の式は最初に評価され、2番目と3番目の式のいずれかが選択されて評価され、選択されて評価された式の結果が条件式全体の値として評価されます.
また、推奨6で詳細に説明されるカンマ演算子には、評価の評価順序が固定されています.
覚えておいてください:
式の計算順序は煩雑ですが、必要な話題です.
オペレータの優先度については、カッコをいくつか書いて、あなたの意図をより明確に表現することをお勧めします.
関数パラメータとオペランドの評価評価評価順序の問題に注意し、そのトラップに注意して、式が計算順序に依存しないようにします.