大規模なC ++ソフトウェア設計ドライブ

こんにちは親愛なる読者。



皆さんの中には、ジョン・ラコスの基本的な仕事である大規模C ++の次の再リリースについてすでに最新のものがあると想定しています







以前の1巻版は20年近く前に発表されましたが、インターネット(およびAmazonでも)には、古い版でさえも十数年以上関連性があったことを説得力を持って証言する多くの肯定的なレビューがあります。 以下に、そのような記事の翻訳を示します。これは、大規模なC ++プロジェクトの物理設計に関する一般的な推奨事項の概要を示しています。 記事があなたの興味を引くことを願っています。来年の新版の翻訳であなたを喜ばせることができるでしょう。





私が偶然読んだC ++プログラミングに関する最も興味深い本の1つは、John Lakosの大規模C ++ソフトウェアデザインです。 1996年にリリースされましたが、残念ながら、C ++での物理設計と、大規模システムに対応するためのそのようなプロジェクトのスケーリングに関する唯一の本です。

それに記載されている原則は、10年以上経っても陳腐化しないのでしょうか? 以下は著者の最も重要なヒントに関する簡単なコメントです。実際のプロジェクトに関するこれらすべてのヒントを確認しました。



用語を扱います







推奨事項





これは、オブジェクト指向設計と物理設計の両方に関する重要な推奨事項の1つです。 このように、コンポーネントの複雑さが部分的に隠されているため、アイデアは良いです。

インスタンス変数をプライベートとして宣言するだけでは、物理的な設計にはまったく影響しませんが、コンパイルファイアウォール(PIMPL / Cheshire cat)を使用してもう1つのステップを踏むと、コンパイル時の依存関係の数を減らして、コンパイル自体を高速化できます。



判定: タクシー







リンクエラーやリンカのバグを回避しながら、非常に簡単に(「静的」を追加するだけで)実行できます。 たとえば、同じ名前で、相互に変換できるパラメーターを持つ一方で、外部バインディングを持つ2つの関数に問題がありました。 実行時に間違った関数が呼び出されましたが、コンパイル中に警告は発生しませんでした。

ここでの唯一の難点は、ほとんどのC ++コンパイラは、匿名の名前空間の文字を含めて、このメソッドが標準のメソッドとして推奨されており、静的メソッドが公式に望ましくない場合でも、



判定: タクシー







本質的には、名前の競合を回避し、翻訳単位間の奇妙な相互作用から身を守ることについて話している。 私はいつもそうしています。



判定: タクシー







上記と同じ考え。 列挙の名前は名前空間ではなく、各列挙の意味はグローバル名前空間で公開されるため、列挙は特に潜行的です。



判定: タクシー







ヘッダーファイル内のマクロは、追跡が非常に困難なバグを引き起こす可能性があります。 古典的な例は、誤って選択された名前を持つマクロで、それを含むコードを誤って変更したり、あまり明白ではないことさえあります:特定のオブジェクトが削除されたときにデバッガーでプログラムがクラッシュしたときに私の同僚がメモリ内の破損した情報に問題があると。 しかし、最も興味深いのは、これはすべての削除操作ではなく、一部の操作でのみ発生したことです。 パッケージAから削除する場合、プログラムは常にクラッシュし、Bから削除する場合も動作し続けるようです。



あなたを苦しめないために、私はあなたに言います:このオブジェクトのいくつかのインスタンス変数をifdef-alします。 パッケージAは、パッケージBからサイズXのオブジェクトを受け取り、サイズX-sizeof(#ifdef-thインスタンス変数)を使用してそれらを削除しようとしたため、削除中に落ちました。



判定: タクシー







このルールは、前のルールに従います。 考え方は、クラス、構造、および関連付けが宣言されると、一種の名前空間を形成し、これが名前の競合を最小限に抑えることです。 演算子関数はファイルスコープで宣言または定義する必要はありませんが、一部の演算子関数はインスタンス関数に変換できないため、選択の余地はありません。



判定: タクシー







実際、ほとんどのプロジェクト(小さなプロジェクトでも)でこれが必要になります。なぜなら、ヘッダーファイルを複数回インクルードすると、コンパイルエラーが発生するからです。 接続セキュリティには、単一の予測可能な名前を付ける必要があることに注意してください。 私はかつて多くの命名規則が適用されたプロジェクトで働いていましたが、多くの混乱がありました。



INC_FILENAME_Hなど、ファイル名から派生したバリエーションを使用するのが好きです。 これを行うために、選択したテキストの接続保護を生成するIDEで小さなマクロを作成しました。



判定: タクシー







評決: 自明







この規則の意味は、不完全なヘッダーファイル(インクルードがないヘッダーファイル)が正常にコンパイルされないようにすることです。 そのようなファイルが最初に含まれている場合、それは間違いなくコンパイルされず、他のヘッダーファイルの後に含まれている場合、ヘッダーにないファイルが含まれている可能性があり、コンパイルは成功します。



このルールは、通常、最初のファイル(例:MSVC stdafx.h)として含まれるプリコンパイル済みヘッダーの使用に反します。 これを行う:最初にプリコンパイル済みヘッダー、次にコンポーネントヘッダー、次にプロジェクトヘッダー、外部ライブラリのヘッダー(例:boost、wxWidgetsなど)、最後にSTL / CRTヘッダーを含めます。 さらに、コンパイラーはそれらをスキップするインテリジェンスを持っているため、プリコンパイル済みヘッダーを構成するファイルを明示的に含めます。必要に応じて、プリコンパイル済みヘッダーなしでコンパイルできます。



判定: タクシー







これらの推奨事項は相互に関連しています。 名前を正しくインポートすると、変更点が1つだけになり、これらの名前の変更にエラーがあると、コンパイルエラーが発生します。 これは、暗黙のインポート操作中に発生する可能性があり、実際に発生します。



判定: タクシー







過度の注意、あなたは思いませんか? ただし、この本は非常に大きなプログラムに関するものであることを忘れないでください。 プロジェクトに数千のファイルがある場合、すべてのファイルの名前を頭に入れられない可能性があり、ガイドラインは非常に役立ちます。



このプラクティスは、次の場合に特に役立ちました。







判定: タクシー







周期的な依存関係-これは良くありません、誰もが同意しますか? 大規模なプロジェクトでは、依存関係を管理することが非常に重要です。何かを見逃すと、モノリスが手に入るからです。



パッケージ間で循環依存関係が発生した場合に発生する可能性のある問題を次に示します。







評決: 信じられないほど操縦







特に、メモリリークを追跡する方がはるかに簡単なので、このようなメモリを解放する必要があります。 ほとんどのメモリ検証ツールは次のように機能します。さまざまな時点でプログラムのメモリのスナップショットを取得します。 静的構造に割り当てられた未割り当てメモリがある場合、これはリークとして認定されます。



さらに、オブジェクトがメモリを使用している場合、プログラマが明示的にメモリを解放するまでデストラクタは呼び出されません。たとえプログラムの終了時にOSがメモリを解放できるとしてもです。

この問題を解決する最も簡単な方法は、auto_ptrやshared_ptrなどのスマートポインターを使用することです。



判定: タクシー



結論



ご覧のとおり、推奨事項のほとんどは依然として関連しています。 Lakosの本は多くの点で、大規模なC ++プログラミングのアイデアを決定しました。これらの推奨事項は、いくつかの実際のプロジェクトで役に立ちました。



All Articles