I: Interfaces
5013 ワード
インタフェースはプログラムの2つの部分間の契約です.サービスプロバイダおよびそのサービスのユーザに対する期待を正確に説明することが重要である.インタフェースの良好な(理解しやすく、有効な使用を奨励し、エラーが発生しにくく、テストをサポートするなど)は、コード組織の最も重要な単一の側面である可能性があります.
I.1:インタフェースを明示化する
Reason
正確性.インタフェースに規定されていない仮定は無視されやすく、テストしにくい.
Example, bad
グローバル(ネーミングスペース範囲)変数(呼び出しモード)によって関数を制御する動作は暗黙的であり、混同を引き起こす可能性があります.例:
呼び出し者にとって、2つの
Exception
環境変数によって、通常の出力やデバッグ、最適化など、一連の操作の詳細を制御する場合があります.非ローカルコントロールを使用すると、混同される可能性がありますが、他の固定的な意味の実装の詳細のみを制御します.
Example, bad
非局所変数(例えば、
ログ出力を生成しないように接続が切断された場合はどうしますか?私に会いましょう.???代替案:例外を放出します.一つの例外は無視できない.代替案:非ローカルまたは暗黙的な状態でインタフェースに情報を伝達しないでください.非constメンバー関数は、オブジェクトのステータスを介して他のメンバー関数に情報を渡すことに注意してください.代替式:インタフェースは関数または関数のセットである必要があります.関数はテンプレート関数であってもよく、関数セットはクラスまたはクラステンプレートであってもよい.
Enforcement(単純)関数は、ネーミングスペースの範囲内で宣言された変数値に基づいて制御フロー決定を行うべきではない. (単純)関数は、ネーミングスペース内で宣言された変数に書くべきではありません.
I.2:非constグローバル変数の使用を避ける
Reason
非
Example, bad
誰が
Note
Global constants are useful.
Note
グローバル変数のルールは、ネーミングスペース範囲変数にも適用されます.
Note
代替方法:グローバル(より一般的なネーミングスペース役割ドメイン)データを使用してレプリケーションを回避する場合は、リファレンスによってconstにデータを渡すことを考慮します.もう1つの解決策は、データをオブジェクトのステータスとして定義し、操作をメンバー関数として定義することです.警告:データ競合に注意:1つのスレッドがローカルでないデータ(または参照によって渡されたデータ)にアクセスでき、別のスレッドが呼び出し元を実行する場合は、データ競合を行うことができます.各ポインタまたは可変データへの参照は、潜在的なデータ競合です.
Note
可変データに競合条件を設定することはできません.References: See the rules for calling functions.
Enforcement
ルールは「don't use」ではなく「avoid」です.もちろん、
Enforcement
(単純)ネーミングスペースの範囲内で宣言されたすべての非const変数.
I.3:一例を避ける
Reason
単一の例は、基本的に複雑な変相グローバルオブジェクトです.
Example
There are many variants of the singleton idea. That's part of the problem.
Note
グローバルオブジェクトを変更しない場合は、
Exception
最初の使用時に初期化を行うには、最も簡単な「単一のインスタンス」を使用します(通常は単一のインスタンスと見なされないほど簡単です).
これは初期化順序に関連する問題の最も有効な解決策の一つである.マルチスレッド環境では、静的オブジェクトの初期化に競合条件は導入されません(コンストラクション関数から共有オブジェクトにアクセスしない限り).ローカル
オブジェクトは、適切なスレッドセキュリティ方式 は、 を破棄する必要がある.
Enforcement
普通は難しいです.検索名 は、単一のオブジェクトのみを作成するクラスを検索します(オブジェクトを計算するか、コンストラクション関数をチェックします). クラスXに共通の静的関数がある場合、クラス'Xクラスの関数が局所的に静的であり、ポインタまたは参照を返す場合は禁止されます.
I.4:インタフェースの種類は明確にしなければならない
Reason
タイプは最も簡単で最高のドキュメントで、定義が良好で、コンパイル時にチェックすることを保証します.さらに、正確なタイプのコードは、通常、より最適化されます.
Example, don’t Consider:
呼び出し元は、データポインタ(後)を正しいタイプに変換して使用する必要があります.これは間違いやすく、常に冗長です.
Alternative:
通常、テンプレートパラメータは、
Example, bad Consider:
Example, bad
Example, good
Enforcement
I.5:独身を避ける
Reason
Example, bad
Exception
Example, bad
Enforcement
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」です.もちろん、
cin
cout
および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
を含むクラス.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