クラス B のコピー コンストラクターと代入演算子を定義する必要があります。そうしないと、これらのポインターで深刻な問題が発生します。これとは別に、行 1 と行 3 の間に機能上の違いはありません。唯一の違いは実装にあります。
そうは言っても、B 内でポインターを使用する理由はありません。固定数の整数が必要な場合は、プレーンな整数またはプレーンな配列を使用してください。可変数の整数が必要な場合は、 を使用しますstd::vector
。また、動的メモリを割り当てる必要がある場合は、細心の注意を払い、スマート ポインターの使用を検討してください。
クラス B に含まれる [ポインタへの] 整数が 1 つだけの場合、次のようになります。
class B
{
private:
int * x;
public:
B (int i) { x = new int(i); }
B (const B & b) { x = new int(*b.x); }
~B() { delete x; }
B & operator= (const B & b) // Corner cases:
{ //
int * p = x; // 1) b and *this might
x = new int(*b.x); // be the same object
delete p; //
return *this; // 2) new might throw
} // an exception
};
このコードは、コメントされたコーナーケースでも「正しいこと (TM)」を実行します。
別のオプションは次のとおりです。
#include <utility> // std::swap
class B
{
private:
int * x;
public:
B (int i) { x = new int(i); }
B (const B & b) { x = new int(*b.x); }
~B() { delete x; }
void swap (B & b)
{
using std::swap;
swap (x, b.x);
}
B & operator= (const B & b) // Corner cases:
{ //
B tmp(b); // 1) b and *this might
swap (tmp); // be the same object
return *this; //
} // 2) new might throw
}; // an exception
ただし、例のように 2 つのポインターがある場合は、new
2 回呼び出す必要があります。2 番目が例外のスローに失敗した場合、最初のメモリによって予約されたメモリnew
を自動的に...delete
new
#include <utility> // std::swap
class B
{
private:
int * x;
int * y;
void init (int i, int j)
{
x = new int(i);
try
{
y = new int(j);
}
catch (...) // first new was OK but
{ // second failed, so undo
delete x; // first allocation and
throw; // continue the exception
}
}
public:
B (int i, int j) { init (i, j); }
B (const B & b) { init (*b.x, *b.y); }
~B() { delete x; delete y; }
void swap (B & b)
{
using std::swap;
swap (x, b.x);
swap (y, b.y);
}
B & operator= (const B & b) // Corner cases:
{ //
B tmp(b); // 1) b and *this might
swap (tmp); // be the same object
return *this; //
} // 2) new might throw
}; // an exception
[ポインタへの] int が 3 つまたは 4 つあると、コードはさらに醜くなります。そこで、スマート ポインターと RAII (Resource Acquisition Is Initialization) が本当に役立ちます。
#include <utility> // std::swap
#include <memory> // std::unique_ptr (or std::auto_ptr)
class B
{
private:
std::auto_ptr<int> x; // If your compiler supports
std::auto_ptr<int> y; // C++11, use unique_ptr instead
public:
B (int i, int j) : x(new int(i)), // If 2nd new
y(new int(j)) {} // fails, 1st is
// undone
B (const B & b) : x(new int(*b.x)),
y(new int(*b.y)) {}
// No destructor is required
void swap (B & b)
{
using std::swap;
swap (x, b.x);
swap (y, b.y);
}
B & operator= (const B & b) // Corner cases:
{ //
B tmp(b); // 1) b and *this might
swap (tmp); // be the same object
return *this; //
} // 2) new might throw
}; // an exception