intポインターメンバー変数「i」を持つ構造体「s」があるとします。s のデフォルト コンストラクターで i のヒープにメモリを割り当てます。後で、コードの他の部分で、s のインスタンスを値で関数に渡します。ここで浅いコピーを行っていますか?コピー コンストラクター、代入演算子、または s の何も実装していないと仮定します...ただの既定のコンストラクターです。
3 に答える
@[don.neufeld.myopenid.com] が言ったことをフォローアップするために、それは浅いコピーであるだけでなく、(選択してください) メモリ リークまたはダングリング ポインターのいずれかです。
// memory leak (note that the pointer is never deleted)
class A
{
B *_b;
public:
A()
: _b(new B)
{
}
};
// dangling ptr (who deletes the instance?)
class A
{
B *_b;
public:
A()
... (same as above)
~A()
{
delete _b;
}
};
これを解決するには、いくつかの方法があります。
生メモリ ポインターを使用するクラスでは、常にコピー コンストラクターと operator= を実装します。
class A
{
B *_b;
public:
A()
... (same as above)
~A()
...
A(const A &rhs)
: _b(new B(rhs._b))
{
}
A &operator=(const A &rhs)
{
B *b=new B(rhs._b);
delete _b;
_b=b;
return *this;
};
言うまでもなく、これは大きな問題であり、正しく行うにはかなりの微妙な点があります。ここでやったかどうかも完全にはわかりませんし、何度かやったことがあります。すべてのメンバーをコピーする必要があることを忘れないでください。後で新しいメンバーを追加する場合は、それらも忘れずに追加してください。
クラスでコピー コンストラクターと operator= private を作成します。これが「ドアをロックする」ソリューションです。シンプルで効果的ですが、過保護になることもあります。
class A : public boost::noncopyable
{
...
};
生のポインターを使用しないでください。これは簡単で効果的です。ここには多くのオプションがあります:
- 生の char ポインターの代わりに文字列クラスを使用する
- std::auto_ptr、boost::shared_ptr、boost::scoped_ptr などを使用する
例:
// uses shared_ptr - note that you don't need a copy constructor or op= -
// shared_ptr uses reference counting so the _b instance is shared and only
// deleted when the last reference is gone - admire the simplicity!
// it is almost exactly the same as the "memory leak" version, but there is no leak
class A
{
boost::shared_ptr<B> _b;
public:
A()
: _b(new B)
{
}
};
はい、それは浅いコピーです。s の 2 つのコピー (呼び出し側に 1 つ、パラメーターとしてスタックに 1 つ) があり、それぞれに同じメモリ ブロックへのポインターが含まれています。
構造体の 2 つのコピーがありs
、それぞれに独自のi
ポインターがありますが、両方のi
ポインターはメモリ内の同じアドレスを指す同じ値を持ちます。つまり、浅いコピーになります。