例外の安全性を維持し、メモリリークなどを回避するために、コピーコンストラクタと代入演算子がC++で実行する必要のあるタスクのリストを記述してください。
4 に答える
最初に、本当にコピーをサポートする必要があることを確認してください。ほとんどの場合はそうではないため、両方を無効にすることが最善の方法です。
場合によっては、ポリモーフィック階層のクラスで複製を提供する必要がある場合があります。その場合は、代入演算子を無効にし、(保護された?) コピー コンストラクターを記述し、仮想 clone() 関数を提供します。
それ以外の場合、値クラスを作成している場合は、コプリエンの直交正則形式の土地に戻っています。自明にコピーできないメンバーがある場合は、コピー コンストラクター、デストラクター、代入演算子、および既定のコンストラクターを提供する必要があります。このルールは改良することができます。例を参照してください: The Law of The Big Two
また、代入演算子に関する C++ FAQ、コピーアンドスワップイディオム、およびGOTW もご覧になることをお勧めします。
コンパイラで生成されたバージョンは、ほとんどの状況で機能します。
オブジェクトに RAW ポインター (RAW ポインターがないことの引数) が含まれている場合、この問題についてもう少し考える必要があります。RAW ポインターを持っているので、2 番目の質問は、ポインターを所有していますか (あなたによって削除されているか) ですか? その場合は、4 のルールを適用する必要があります。
複数の RAW ポインターを所有することは、正しく行うことがますます難しくなります (複雑さの増加も線形ではありません [しかし、それは観察に基づくものであり、そのステートメントを裏付ける実際の統計はありません])。したがって、複数の RAW ポインターがある場合は、それぞれを独自のクラス (何らかの形式のスマート ポインター) にラップすることを検討してください。
ルール 4: オブジェクトが RAW ポインターの所有者である場合、メモリ管理を正しく処理するために、次の 4 つのメンバーを定義する必要があります。
- コンストラクタ
- コンストラクターのコピー
- 代入演算子
- デストラクタ
これらをどのように定義するかは、状況によって異なります。ただし、次の点に注意してください。
- デフォルトの構築: ポインターを NULL に設定する
- コピー コンストラクター: コピー アンド スワップ イデウムを使用して、「強力な例外保証」を提供します。
- 代入演算子: 自己への代入をチェック
- デストラクタ: デストラクタから例外が伝播するのを防ぎます。
これを読んでみてください。
http://www.icu-project.org/docs/papers/cpp_report/the_anatomy_of_the_assignment_operator.html
代入演算子の非常に優れた分析です
ここで安全に例外についてはわかりませんが、この方法で行きます。テンプレート化された配列ラッパーだとしましょう。それが役に立てば幸い :)
Array(const Array& rhs)
{
mData = NULL;
mSize = rhs.size();
*this = rhs;
}
Array& operator=(const Array& rhs)
{
if(this == &rhs)
{
return *this;
}
int len = rhs.size();
delete[] mData;
mData = new T[len];
for(int i = 0; i < len; ++i)
{
mData[i] = rhs[i];
}
mSize = len;
return *this;
}