問題の背景:
C++は、数値、文字、配列といった小さなセットの組み込み型を提供するCに基づいて構築されました。言語の発展とともに、構造体、クラス、列挙型といった概念が追加され、これらはユーザー定義型になりました。
問題:
プログラムにおけるデータ型は、変数が占めるメモリ量、初期化方法、コピー方法、破棄方法、比較方法を定義します。組み込み型は標準で定められた動作を持っていますが、ユーザー定義型はすべての側面を明示的に定義する必要があります。ユーザー定義型の管理における誤りは、クラッシュやメモリリーク、不正なオブジェクト比較などにつながる可能性があります。
解決策:
組み込み型はint、float、double、char、boolおよびその他の「原始型」です。ユーザー定義型は、あなたが作成した任意の構造体、クラス、共用体です。複雑な問題に対処するには、正確なコピー、比較、リソース管理のセマンティクスを持つユーザー定義型を導入する必要があります。
コード例:
// 組み込み型 int x = 5; // ユーザー定義型 struct Point { double x, y; }; Point a = {1.0, 2.0}; // リソースを持つクラス class MyFile { public: MyFile(const std::string& fn) : f(fopen(fn.c_str(), "r")) {} ~MyFile() { if (f) fclose(f); } private: FILE* f; };
ユーザー定義型は組み込み型のように完全に動作できますか?(たとえば、==で比較できますか?)
いいえ、==による比較はC++20からデフォルトのoperator==を介してのみ動作し、それ以前は明示的な定義が必要でした。
生ポインタ(int、FILEなど)のみを保持するクラスでは、コピーコンストラクタやデストラクタを実装しなくてもよいですか?**
いいえ、その場合、デフォルトでは浅いコピーが行われ、メモリ/リソースのリークや二重解放を引き起こす可能性があります。「ファイブの法則」を実装する必要があります。
構造体のデフォルト値はゼロで初期化されますか(Point p;)?
いいえ、ローカル構造体は未初期化になる可能性があり、メモリの内容はランダムです。明示的に初期化を使用してください。
ネガティブケース:
ファイルのラッパークラスがデストラクタを実装しなかった。プログラムは、ファイル記述子を閉じずに何千ものファイルを処理し続けた。
長所: コードが少なく、見た目がシンプル 短所: リソースのリーク、不安定な動作
ポジティブケース:
クラスがRAIIを実装している — コンストラクタでファイルが開かれ、デストラクタで閉じられ、コピーが禁止されている。
長所: 信頼性、安全性、クリーンなインターフェース 短所: 「ファイブの法則」を覚えておく必要があり、より多くのコードを書く必要がある。