私は大学で、常に未使用のオブジェクトを解放する必要があることを学びましたが、実際に解放する方法は必要ありません。たとえば、コードを正しく構造化するなどです。C++ でポインターを処理する方法に関する一般的な規則はありますか?
現在、ブーストの使用は許可されていません。私が使用しているフレームワークではジェネリックの使用が禁止されているため、純粋な C++ に固執する必要があります。
私は組み込みの Symbian OS を使用してきました。この OS は、完全に開発者の慣例に基づいて、このための優れたシステムを備えていました。
基本的に、クラスが単純に何かを使用する場合は、参照を使用します。クラスが何かを所有している場合、ポインターを使用します。
これは美しく機能し、使用するのが楽しみでした。メモリの問題は非常にまれでした。
ルール:
誰かがルール 1 を許可しない場合、他の人のコードを入手して変数名を変更し、著作権表示を削除しても、誰も気付かないことを覚えておいてください。学校のプロジェクトでない限り、非常に洗練されたツールを使用して、実際にそのような悪ふざけをチェックします。この質問も参照してください。
ここに別のルールを追加します。
C++ を初めて使用するプログラマー、または Java のような言語からやって来たプログラマーは、コンテキストに関係なく、オブジェクトを作成したいときはいつでも new について学習し、それを執拗に使用しているようです。これは、オブジェクトが関数内でローカルに作成され、何か有用なことを純粋に行う場合に特に有害です。このように new を使用すると、パフォーマンスが低下する可能性があり、対応する削除が忘れられたときにばかげたメモリ リークが発生しやすくなります。はい、スマート ポインターは後者に役立ちますが、パフォーマンスの問題は解決しません (new/delete または同等のものが舞台裏で使用されていると仮定します)。興味深いことに (おそらく)、Visual C++ を使用する場合、delete は new よりもコストがかかる傾向があることがわかりました。
この混乱の一部は、それらが呼び出す関数がポインター、またはスマートポインターを引数として取る可能性があるという事実からも生じます (参照の方がおそらくより適切/明確である場合)。これにより、関数にポインターを渡すことができるようにするには、ポインターを「作成」する必要があると考えるようになります (多くの人は、これが new の機能だと考えているようです)。明らかに、これには API の記述方法に関するいくつかの規則が必要であり、呼び出し規約を可能な限り明確にする必要があります。これは、関数プロトタイプで提供される明確なコメントで強化されます。
一般的なケース (リソースが必ずしもメモリではないリソース管理) では、RAII パターンに精通している必要があります。これは、C++ 開発者にとって最も重要な情報の 1 つです。
一般に、必要な場合を除き、ヒープからの割り当ては避けてください。必要に応じて、有効期間が長く、コードのさまざまな部分で共有する必要があるオブジェクトに対して参照カウントを使用します。
オブジェクトを動的に割り当てる必要がある場合もありますが、それらは特定の期間内でのみ使用されます。たとえば、以前のプロジェクトでは、データベース スキーマの複雑なメモリ内表現を作成する必要がありました。基本的には、オブジェクトの複雑な循環グラフです。ただし、グラフはデータベース接続中にのみ必要であり、その後はすべてのノードを 1 回で解放できました。この種のシナリオで使用するのに適したパターンは、私が「ローカル GC イディオム」と呼んでいるものです。それが「正式な」名前であるかどうかはわかりません。これは、私自身のコードと Cocoa でしか見たことがないためです ( Apple の Cocoa リファレンスのNSAutoreleasePoolを参照してください)。
簡単に言えば、new を使用して割り当てた一時オブジェクトへのポインターを保持する「コレクター」オブジェクトを作成します。これは通常、プログラム内の何らかのスコープに結び付けられます。静的スコープ (例: RAII イディオムを実装するスタック割り当てオブジェクトとして) または動的スコープ (例: データベース接続の有効期間に結び付けられる) のいずれかです。私の以前のプロジェクト)。「コレクター」オブジェクトが解放されると、そのデストラクタはそれが指すすべてのオブジェクトを解放します。
また、DrPizza のように、テンプレートを使用しないという制限は厳しすぎると思います。しかし、Solaris、AIX、および HP-UX の古いバージョンで多くの開発を行ってきたので (つい最近 - そうです、これらのプラットフォームはまだフォーチュン 50 に含まれています)、移植性を本当に気にかけているのであれば、テンプレートの使用は最小限にする必要があります。ただし、コンテナーとスマートポインターにそれらを使用することは問題ないはずです (私にとってはうまくいきました)。テンプレートがなければ、私が説明した手法を実装するのはより困難です。「コレクター」によって管理されるすべてのオブジェクトは、共通の基本クラスから派生する必要があります。
G'day、
ScottMeyersによる「EffectiveC++」の関連セクションを読むことをお勧めします。読みやすく、彼は不注意をトラップするためのいくつかの興味深い落とし穴をカバーしています。
テンプレートがないことにも興味があります。したがって、STLやブーストはありません。わお。
ところで、人々に慣習に同意してもらうことは素晴らしい考えです。誰もがOODの慣習に同意するようになっています。ところで、Effective C ++の最新版には、初版にあったOOD規則に関する優れた章がありません。これは残念です。たとえば、パブリック仮想継承などの規則は常に「isa」関係をモデル化します。
ロブ
(ref()/unref() メソッドとカウンターを使用して) 機能のようなスマート ポインターを実装するいくつかの基本クラスからすべてを派生させることができます。
@Timbo によって強調表示されたすべてのポイントは、その基本クラスを設計するときに重要です。