私は最近、「クラスのヒープ割り当ての防止」について多くのことを読みました (この質問を参照してください)。
「どのように」は理解できたが、 「なぜ」誰かがそれをしたいのか、今となっては理解できない。
これには正当な理由があるに違いないと思いますが、それを理解することはできません。
要するに、「ユーザーが自分のクラスのオブジェクトをヒープに作成することを禁止したいのはなぜですか?」
私は最近、「クラスのヒープ割り当ての防止」について多くのことを読みました (この質問を参照してください)。
「どのように」は理解できたが、 「なぜ」誰かがそれをしたいのか、今となっては理解できない。
これには正当な理由があるに違いないと思いますが、それを理解することはできません。
要するに、「ユーザーが自分のクラスのオブジェクトをヒープに作成することを禁止したいのはなぜですか?」
一部のクラスは、オブジェクトがスタック上でインスタンス化されている場合にのみ意味があります。たとえば、ブーストscoped_ptrまたはlock_guard。
主な理由は、スタックに割り当てられたオブジェクトがスコープ外になると自動的にクリーンアップされ、大きなクラスのバグ (メモリ割り当てのバグ) が取り除かれるためです。
私は流れに逆らうつもりです(だから私は反対票を期待していますが、その理由を示すためにコメントを残してください).
ヒープの割り当てを禁止する理由がわかりません。主な理由は、作成したクラスの潜在的な用途を推測したくないからです。
設計規則として、私は自分のクラスの使用に対する制限をできるだけ少なくする傾向があります。これは、仮定をできるだけ少なくすることを意味します。禁止されているという理由だけで、自分のやりたいことができないことほど腹立たしいことはありません...理由は不明であるか、単に間違っているためです(ライブラリライターの迷信的/誤った信念を示しています)。
また、プラグマティズムは、C++ で実際に何かを防ぐことはほぼ不可能であると教えています。たとえば、ガードについて話している人もいます --> スーパークラスを作成したい場合はどうすればよいですか (便利なようにロギングを追加します)。次に、ガード クラスを属性として配置します。その (元のクラスの)new
演算子がプライベートであっても、何らかの方法でメカニズムを複製しない限り、スーパー クラスをヒープ上でインスタンス化できます。
ですから、私にとっては、理由や方法の問題ではありません。ライブラリコードのメモリ割り当てスキームをいじったりはしません。ユーザーにとって最も便利なものを使用するのはユーザー次第です。
通常、クラスの予期しない使用を防止することをお勧めします。たとえば、RAII 手法に依存する Guard クラスを考えてみましょう。それらはスタックに割り当てられる必要があり、スコープ外になるとジョブを実行します。ユーザーがガード オブジェクトをヒープに割り当てることを期待する人はいないため、明示的に禁止されています。
暗黙的よりも明示的。Herb Shutter は、クラスを間違って使用する (ヒープに割り当てる) ことは難しく、正しく (スタック上で) 使用するのは非常に簡単であるに違いないと述べています。
スタック割り当てが高速になります (スペースの検索は不要です)。
非常に小さなオブジェクトの特定のクラス (ジオメトリ エンジンの 3D ポイントを検討してください) の場合、これらをヒープに個別に割り当てると、ダングリング ポインターが作成され、大量のオーバーヘッドが発生しますが、多くの計算では非常に必要です。
したがって、一般的なメカニズムは、幾何学的エンティティの記述のように、3D ポイントのコレクションを実際に含むオブジェクトで flyweight パターンを使用し、計算の中間結果としてヒープで使用できるようにすることです。
とはいえ、フライウェイトの実装間でデータを不必要にコピーしないように特別な注意を払う必要があります。
一般に、フライウェイト パターンとヒープ割り当て機能を組み合わせて最適な結果を達成する多くのケースを見つけました。フライウェイトは永続的なストレージを提供し、ヒープ割り当てにより、別のフライウェイトを生成することなくアイテム レベルの操作を実行できます。