C ++のシャローコピーに関する質問
-
03-07-2019 - |
質問
構造体" s"があるとしますintポインターメンバー変数" i"を使用します。 sのデフォルトコンストラクターでiのヒープにメモリを割り当てます。後でコードの他の部分で、値によってsのインスタンスを関数に渡します。ここで浅いコピーをしていますか?コピーコンストラクタまたは代入演算子、またはsの何かを実装しなかったと仮定します。デフォルトコンストラクタだけです。
解決
@ [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;
}
};
これを解決するには、いくつかの方法があります。
rawメモリーポインターを使用するクラスでは、常にコピーコンストラクターと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 =をクラスでプライベートにします。これは「ドアをロックする」です。溶液。シンプルで効果的ですが、保護が強すぎる場合があります。
class A : public boost::noncopyable
{
...
};
生のポインタを使用しないでください。これは簡単で効果的です。ここには多くのオプションがあります:
- 生の文字ポインタの代わりに文字列クラスを使用する
- 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つ)があり、それぞれに同じメモリブロックへのポインターが含まれています。
s
構造体の2つのコピーがあり、それぞれに独自の i
ポインターがありますが、両方の i
ポインターにはメモリ内の同じアドレスを指す同じ値-そう、それは浅いコピーになります。