質問

私は大学で、未使用のオブジェクトを常に解放する必要があることを学びましたが、実際にそれを行う方法はわかりませんでした。たとえば、コードを正しく構造化するなどです。C++ でポインターを処理する方法に関する一般的な規則はありますか?

現在ブーストを使用することはできません。私が使用しているフレームワークではジェネリックスの使用が禁止されているため、純粋な C++ に固執する必要があります。

役に立ちましたか?

解決

私は組み込みの Symbian OS を使用してきましたが、この OS には完全に開発者の規約に基づいた、このための優れたシステムが用意されていました。

  1. ポインタを所有できるのは 1 つのオブジェクトだけです。デフォルトでは、これが作成者です。
  2. 所有権を譲渡することができます。所有権の譲渡を示すために、オブジェクトはメソッド シグネチャ内のポインターとして渡されます (例:void Foo(Bar *zonk);)。
  3. オブジェクトをいつ削除するかは所有者が決定します。
  4. オブジェクトを使用するためだけにメソッドに渡すには、オブジェクトはメソッド シグネチャの参照として渡されます (例:void Foo(Bat &zonk);)。
  5. 非所有者クラスは、所有者が使用中にオブジェクトを破棄しないことが確実な場合にのみ、与えられたオブジェクトへの参照を格納できます (ポインタは使用できません)。

基本的に、クラスが単に何かを使用する場合、参照を使用します。クラスが何かを所有する場合、ポインターを使用します。

これは美しく機能し、使用するのが楽しかったです。メモリの問題は非常にまれでした。

他のヒント

ルール:

  1. 可能な限り、スマートポインター. 。ブーストにはいくつかの機能があります良いもの.
  2. スマートポインターを使用できない場合は、 ポインターを削除した後、ポインターを削除します.
  3. ルール 1 を使用できない場所では決して作業しないでください。

誰かがルール 1 を禁止した場合、他人のコードを取得し、変数名を変更し、著作権表示を削除しても、誰も気付かないことを覚えておいてください。それが学校のプロジェクトで、非常に洗練されたツールを使用してその種の不正行為がないか実際にチェックする場合は別です。こちらも参照してください。 この質問.

ここに別のルールを追加します。

  • 自動オブジェクトが問題なく機能する場合は、オブジェクトを新規作成/削除しないでください。

C++ を初めて使用するプログラマ、または Java などの言語から来たプログラマは、新しいことを学び、コンテキストに関係なく、オブジェクトを作成するときはいつでもそれを執拗に使用するようであることがわかりました。これは、純粋に何か役に立つことを目的としてオブジェクトが関数内でローカルに作成される場合に特に有害です。この方法で new を使用すると、パフォーマンスに悪影響を及ぼす可能性があり、対応する削除を忘れたときに愚かなメモリ リークが発生しやすくなります。はい、スマート ポインターは後者には役立ちますが、パフォーマンスの問題は解決されません (new/delete または同等の機能が舞台裏で使用されていると仮定します)。興味深いことに (おそらく)、Visual C++ を使用する場合、削除は新規作成よりもコストが高くなる傾向があることがわかりました。

この混乱の一部は、呼び出される関数がポインター、さらにはスマート ポインターを引数として受け取る可能性があるという事実からも発生します (参照の方が適切/明確な場合)。このため、関数にポインタを渡すためにはポインタを「作成」する必要があると考えるようになります (これが new の機能だと多くの人が考えているようです)。これには、呼び出し規約を可能な限り明確にするために API の記述方法に関するいくつかのルールが必要であることは明らかであり、関数プロトタイプで提供される明確なコメントで強化されています。

一般的なケース (リソース管理、リソースが必ずしもメモリであるとは限らない) では、 RAIIパターン. 。これは、C++ 開発者にとって最も重要な情報の 1 つです。

一般に、必要な場合を除き、ヒープからの割り当ては避けてください。必要に応じて、有効期間が長く、コードのさまざまな部分間で共有する必要があるオブジェクトに対して参照カウントを使用します。

オブジェクトを動的に割り当てる必要がある場合がありますが、それらは特定の期間内でのみ使用されます。たとえば、以前のプロジェクトでは、データベース スキーマの複雑なメモリ内表現 (基本的にはオブジェクトの複雑な循環グラフ) を作成する必要がありました。ただし、グラフが必要となるのはデータベース接続の間だけであり、その後はすべてのノードを一度に解放できます。この種のシナリオでは、使用するのに適したパターンは、私が「ローカルGCイディオム」と呼ぶものです。 「公式」の名前があるかどうかはわかりません。自分のコードとcocoaでしか見たものです(参照 NSAutoreleasePool Apple の Cocoa リファレンスに記載されています)。

簡単に言うと、new を使用して割り当てた一時オブジェクトへのポインタを保持する「コレクター」オブジェクトを作成します。通常、これはプログラム内の何らかのスコープ (静的スコープ (例:-- RAII イディオムを実装するスタック割り当てオブジェクトとして)、または動的オブジェクト (例:-- 以前のプロジェクトと同様、データベース接続の存続期間に関連付けられています)。「コレクター」オブジェクトが解放されると、そのデストラクターはそれが指すすべてのオブジェクトを解放します。

また、DrPizzaのように、テンプレートを使用しないという制限は厳しすぎると思います。ただし、Solaris、AIX、および HP-UX の古いバージョンで多くの開発を行ってきたので (つい最近 - はい、これらのプラットフォームはフォーチュン 50 にまだ残っています)、移植性を本当に重視するのであれば、テンプレートの使用はできるだけ少なくする必要があります。ただし、コンテナーやスマート ポインターに使用しても問題ないはずです (私にとってはうまくいきました)。テンプレートがなければ、私が説明したテクニックを実装するのはさらに困難になります。「コレクター」によって管理されるすべてのオブジェクトが共通の基本クラスから派生する必要があります。

こんにちは、

Scott Meyers の「Effective C++」の関連セクションを読むことをお勧めします。読みやすく、不注意な人を罠にはめるための興味深い落とし穴をいくつか取り上げています。

テンプレートがないのも気になります。したがって、STLやブーストはありません。おお。

ところで、人々に慣例について同意してもらうのは素晴らしいアイデアです。OOD の規約について全員の合意を得ることも同様です。ところで、Effective C++ の最新版には、初版にあった OOD 規約に関する優れた章がありませんが、残念です。パブリック仮想継承などの規則 いつも 「isa」関係をモデル化します。

ロブ

  • メモリを手動で管理する必要がある場合は、同じスコープ/関数/クラス/モジュールで削除を呼び出すことを確認してください。これは最初に適用されます。
  • 関数の発信者に、それによって満たされたメモリを割り当ててもらい、新しいポインターを返さないでください。
  • new を呼び出したときと同じ exe/dll で delete を常に呼び出してください。そうしないと、ヒープ破損 (互換性のないランタイム ライブラリが異なる) の問題が発生する可能性があります。

スマート ポインターのような機能を実装する基本クラスからすべてを派生できます (ref()/unref() メソッドとカウンターを使用)。

@Timbo によって強調表示されているすべての点は、その基本クラスを設計する際に重要です。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top