I: Interfaces

5013 ワード

インタフェースはプログラムの2つの部分間の契約です.サービスプロバイダおよびそのサービスのユーザに対する期待を正確に説明することが重要である.インタフェースの良好な(理解しやすく、有効な使用を奨励し、エラーが発生しにくく、テストをサポートするなど)は、コード組織の最も重要な単一の側面である可能性があります.
I.1:インタフェースを明示化する
Reason
正確性.インタフェースに規定されていない仮定は無視されやすく、テストしにくい.
Example, bad
グローバル(ネーミングスペース範囲)変数(呼び出しモード)によって関数を制御する動作は暗黙的であり、混同を引き起こす可能性があります.例:
int round(double d)
{
    return (round_up) ? ceil(d) : d;    // don't: "invisible" dependency
}

呼び出し者にとって、2つのround(7.2)呼び出しの意味は、異なる結果をもたらす可能性があるが、明らかではない.
Exception
環境変数によって、通常の出力やデバッグ、最適化など、一連の操作の詳細を制御する場合があります.非ローカルコントロールを使用すると、混同される可能性がありますが、他の固定的な意味の実装の詳細のみを制御します.
Example, bad
非局所変数(例えば、errno)による報告は無視されやすい.例:
// don't: no test of printf's return value
fprintf(connection, "logging: %d %d %d
", x, y, s);

ログ出力を生成しないように接続が切断された場合はどうしますか?私に会いましょう.???代替案:例外を放出します.一つの例外は無視できない.代替案:非ローカルまたは暗黙的な状態でインタフェースに情報を伝達しないでください.非constメンバー関数は、オブジェクトのステータスを介して他のメンバー関数に情報を渡すことに注意してください.代替式:インタフェースは関数または関数のセットである必要があります.関数はテンプレート関数であってもよく、関数セットはクラスまたはクラステンプレートであってもよい.
Enforcement
  • (単純)関数は、ネーミングスペースの範囲内で宣言された変数値に基づいて制御フロー決定を行うべきではない.
  • (単純)関数は、ネーミングスペース内で宣言された変数に書くべきではありません.

  • I.2:非constグローバル変数の使用を避ける
    Reason
    constグローバル変数は依存関係を非表示にし、依存関係を予測不可能に変更します.
    Example, bad
    struct Data {
        // ... lots of stuff ...
    } data;            // non-const data
    
    void compute()     // don't
    {
        // ... use data ...
    }
    
    void output()     // don't
    {
        // ... use data ...
    }
    

    誰がdataを修正することができますか?
    Note
    Global constants are useful.
    Note
    グローバル変数のルールは、ネーミングスペース範囲変数にも適用されます.
    Note
    代替方法:グローバル(より一般的なネーミングスペース役割ドメイン)データを使用してレプリケーションを回避する場合は、リファレンスによってconstにデータを渡すことを考慮します.もう1つの解決策は、データをオブジェクトのステータスとして定義し、操作をメンバー関数として定義することです.警告:データ競合に注意:1つのスレッドがローカルでないデータ(または参照によって渡されたデータ)にアクセスでき、別のスレッドが呼び出し元を実行する場合は、データ競合を行うことができます.各ポインタまたは可変データへの参照は、潜在的なデータ競合です.
    Note
    可変データに競合条件を設定することはできません.References: See the rules for calling functions.
    Enforcement
    ルールは「don't use」ではなく「avoid」です.もちろん、cincoutおよびcerrのような(珍しい)例外があります.
    Enforcement
    (単純)ネーミングスペースの範囲内で宣言されたすべての非const変数.
    I.3:一例を避ける
    Reason
    単一の例は、基本的に複雑な変相グローバルオブジェクトです.
    Example
    class Singleton {
        // ... lots of stuff to ensure that only one Singleton object is created,
        // that it is initialized properly, etc.
    };
    

    There are many variants of the singleton idea. That's part of the problem.
    Note
    グローバルオブジェクトを変更しない場合は、constまたはconstexprと宣言します.
    Exception
    最初の使用時に初期化を行うには、最も簡単な「単一のインスタンス」を使用します(通常は単一のインスタンスと見なされないほど簡単です).
    X& myX()
    {
        static X my_x {3};
        return my_x;
    }
    

    これは初期化順序に関連する問題の最も有効な解決策の一つである.マルチスレッド環境では、静的オブジェクトの初期化に競合条件は導入されません(コンストラクション関数から共有オブジェクトにアクセスしない限り).ローカルstaticの初期化は、競合条件を意味しないことに注意してください.しかし、Xの破棄が同期を必要とする操作に関連する場合は、あまり簡単ではないソリューションを使用する必要があります.例:
    X& myX()
    {
        static auto p = new X {3};
        return *p;  // potential leak
    }
    

    オブジェクトは、適切なスレッドセキュリティ方式deleteでなければならない.これは間違いやすいので、私たちはその技術を使用しません.
  • myXはマルチスレッドコード、
  • は、Xオブジェクト(例えば、リソースを解放するため)
  • を破棄する必要がある.
  • Xの構造関数コードは同期する必要がある.多くの人のように単一のインスタンスを1つのオブジェクトのみを作成するクラスとして定義した場合、myXのような関数は単一のインスタンスではなく、この有用なテクノロジーは単一のルールではない例外ではありません.

  • Enforcement
    普通は難しいです.
  • 検索名singletonを含むクラス.
  • は、単一のオブジェクトのみを作成するクラスを検索します(オブジェクトを計算するか、コンストラクション関数をチェックします).
  • クラスXに共通の静的関数がある場合、クラス'Xクラスの関数が局所的に静的であり、ポインタまたは参照を返す場合は禁止されます.

  • I.4:インタフェースの種類は明確にしなければならない
    Reason
    タイプは最も簡単で最高のドキュメントで、定義が良好で、コンパイル時にチェックすることを保証します.さらに、正確なタイプのコードは、通常、より最適化されます.
    Example, don’t Consider:
    void pass(void* data);    // void* is suspicious
    

    呼び出し元は、データポインタ(後)を正しいタイプに変換して使用する必要があります.これは間違いやすく、常に冗長です.void *、特にインタフェースでは避けます.変数やポインタの代わりに使用することを考慮します.
    Alternative:
    通常、テンプレートパラメータは、void *がT&またはT*に変換することを排除することができ、これらのTsは、汎用コードまたは概念制約のテンプレートパラメータであってもよい.
    Example, bad Consider:
    void draw_rect(int, int, int, int);   // great opportunities for mistakes
    
    draw_rect(p.x, p.y, 10, 20);          // what does 10, 20 mean?
    
    intは任意の形式の情報を携帯することができるので、4つのintの意味を推測しなければならない.最も可能性のあるのは、最初の2つはxで、y座標は正しいですが、最後の2つは何ですか?コメントとパラメータ名はヘルプですが、次のことを明確にできます.
    void draw_rectangle(Point top_left, Point bottom_right);
    void draw_rectangle(Point top_left, Size height_width);
    
    draw_rectangle(p, Point{10, 20});  // two corners
    draw_rectangle(p, Size{10, 20});   // one corner and a (height, width) pair
    

    Example, bad
    Example, good
    Enforcement
    I.5:独身を避ける
    Reason
    Example, bad
    Exception
    Example, bad
    Enforcement