More Effective C++第4部効率

5153 ワード

16.80-20の法則を肝に銘じる
プログラムの80%の時間は20%のコードに費やされ、盲目的な最適化プログラムは性能の著しい改善をもたらすことはなく、まずプログラムアナライザを借りてその20%のコードを探して、それに対して最適化を実行しなければならない.
17.緩式評価(lazy evaluation)の使用を検討する
緩式評価のより一般的な説は遅延戦術だ.演算結果が切実に必要とされるまで演算を遅らせることで、結果を得るのに無駄な計算を避けることができます.例えば標準ライブラリのstring
String s1 = "HH";
String s2 = s1;

この2つの文を実行した後、s 2はs 1のコピーをコピーするのではなく、s 2とs 1が文字列HHを共有していることを記録するだけです.s 2の内容を必ずしも変更するわけではありません(s 2の内容を読むだけで依然として共有されている文字列を読む場合)、最初の時間にs 1のcopyをs 2に与えると、不要なcopyコストをもたらす可能性があります.したがって、s 2の内容が変更されるまで、s 1 copyはs 2に与えられる.
緩式取出Lazy Fetching
オブジェクトのコンテンツをネットワークを介してデータベースから取り出す必要がある場合は、オブジェクト全体の情報をすべて取り出すのではなく、使用する必要がある一部だけを取り出すことができます.このオブジェクトの内容は空に初期化され、あるメンバーが使用する必要があるときにメンバーを初期化します.これにより、const関数でもmutableを使用して変数をconst関数内で値を変更することができます.
mutable int* data;

式の評価猶予
本で示した例は,マトリクスを計算する際に最初から計算が完了するのではなく,その結果を使用する必要がある場合に必要な一部だけを計算することで,効率を大幅に向上させることができる.
18.償却予定の計算コスト
超急評価over-eager evaluation
超急評価と緩式評価は相対的であり、超急評価とは、実行時に特定のデータを維持し続け、使用されなくても、これらのデータが頻繁に使用され、その平均コストが緩式評価よりも低くなることを意味する.
19.一時オブジェクトのソースを知る
一時オブジェクトとは、名前の付いていないnon-heap objectを指し、通常は暗黙的なタイプ変換と関数戻りオブジェクトで発生します.これらのオブジェクトの生成と破棄のコストは、プログラムに影響を与える可能性があります.
関数パラメータが入力パラメータタイプと一致しないが、変換可能である場合、伝達方式がreference-to-non-constでない限り、暗黙的なタイプ変換が発生して一時オブジェクトが生成されます.たとえば
void func(const string& str);

char c[10];
func(c);//   string      

伝達方式がreference-to-non-constの場合、プログラマが元のオブジェクトではなく、一時的なオブジェクトを暗黙的に変換することを望んでいるため、一時的なオブジェクトは生成されません.ただし、reference-to-constはconstプロパティのため、関数呼び出しのために一時オブジェクトを生成する必要はありません.
関数は、次の章でオブジェクトによって生成された一時オブジェクトの問題を返します.
20.戻り値最適化の完了に協力する(RVO)
operator*などのby valueで返さなければならない関数もありますが、by valueで返さないことを考慮する必要はありません.一時オブジェクトの戻り方を避ける:return文でオブジェクトを構築し、コンパイラが最適化できるようにする
const A operator*(const A& lhs, const A& rhs){
    return A( lhs.num() * rhs.num() );
}

A a(1);
A b(2);
A c = a * b;

このように書き方は、copyからcへの一時的なオブジェクトを生成するのではなく、コンパイラをc上で直接構築することができる.
21.リロード技術による暗黙型変換の回避
class UPInt{
public:
    UPInt(int val);
};

const UPInt operator+(const UPInt& lhs, const UPInt& rhs);

UPInt upi1,upi2
UPInt upi3 = upi1 + upi2;
upi3 = upi1 + 10;//           10   UPInt   
upi3 = 10 + upi2;//           10   UPInt   

リロード・テクノロジーを使用すると、一時的なオブジェクトのオーバーヘッドを回避できます.
const UPInt operator+(const UPInt& lhs, int rhs);
const UPInt operator+(int lhs, const UPInt& rhs);
//               。

リロードを使用すると、プログラムの効率が向上しない限り、コード量が増加します.
22.オペレータ複合形式(op=)でその独身形式(op)に取って代わることを考慮する
複合形式とは+=,−=のようなオペレータ,独身形式である+,−のようなオペレータを指す.独身の代わりに複合形式を使用する方法:
class A{
public:
    A& operator+=(const A& rhs);
};
const A operator(const A& lhs, const A& rhs){
    retuen A(lhs) += rhs;// lhs    (     , 20),   +=
}

このようにするメリットは:1.結果を左端変数に直接書き込むため、複合オペレータは効率的です.一方、独身オペレータには一時的なオブジェクトが必要です.2.コードの重複を減らし、メンテナンスを容易にする.
23.他のライブラリの使用を検討する
パフォーマンスのボトルネックがライブラリ内の関数にあることを特定するには、ライブラリがどこでも効率的ではないため、ライブラリを交換して効率を向上させることを考慮します.
24.virtual function,multiple inheritance,virtual base classes,runtime type identificationのコストを理解する
この章の内容はInside c++object modelが対象モデルを深く理解している本で詳しく紹介されていますが、私のブログではこの本のノートがあります.