web-dev-qa-db-ja.com

ポインターを使用してコンストラクターをコピーする

最近、クラス内にポインターがある場合、Copyコンストラクターを指定する必要があることを発見しました。

それを学ぶために、以下の簡単なコードを作成しました。コンパイルはしますが、コピーコンストラクターを実行するとランタイムエラーが発生します。

コピーしたオブジェクトのポインターから値だけをコピーしようとしていますが、同じアドレスを割り当てないようにしています。

では、ここで何が問題になっていますか?

    class TRY{
        public:
        TRY();
    ~TRY();
        TRY(TRY const &);

        int *pointer;

        void setPointer(int);
    };


    void TRY::setPointer(int a){
        *pointer = a;

        return;
    }


    TRY::TRY(){}


    TRY::~TRY(){}


    TRY::TRY(TRY const & copyTRY){
        int a = *copyTRY.pointer;
        *pointer = a;
    }



    int main(){

        TRY a;
        a.setPointer(5);

        TRY b = a;

        b.setPointer(8);

        cout << "Address of object a = " << &a << endl;
        cout << "Address of object b = " << &b << endl;

        cout << "Address of a.pointer = " << a.pointer << endl;
        cout << "Address of b.pointer = " << b.pointer << endl;

        cout << "Value in a.pointer = " << *a.pointer << endl;
        cout << "Value in b.pointer = " << *b.pointer << endl;

        return 0;
    }

多くのポインターが含まれている他のクラスにも、この概念を使用して、オブジェクトから他のすべての値をコピーする必要があります。このコードでは最初はコピーが必要なので、コピーの可能性を維持したいと思います(コピーコンストラクターをプライベートとして非表示にすることはしません)。

その上、私が実装する必要のある実際のクラスには10個のポインターがあり、時間とともに変化する可能性があります。 C++でディープコピーコンストラクターを作成するためのややスマートな方法はありませんか?...

15
Biga

ステートメントint* pointerポインタを定義しましたが、メモリを割り当てていません。最初に、次のようにメモリを割り当てることで、適切なメモリ位置を指すようにする必要があります:int* pointer = new int。次に、コピーコンストラクターで、コピーしたオブジェクトにメモリを割り当てる必要があります。また、デストラクタで削除を使用してメモリを解放することを忘れないでください。

この例が役立つことを願っています:

class B
{

public:
    B();
    B(const B& b);
    ~B();
    void setVal(int val);

private:
    int* m_p;
};

B::B() 
{
    //Allocate the memory to hold an int
    m_p = new int;

    *m_p = 0;
}

B::B(const B& b)
{
    //Allocate the memory first
    m_p = new int;

    //Then copy the value from the passed object
    *m_p = *b.m_p;
}

B::~B()
{

    //Release the memory allocated
    delete m_p;
    m_p = NULL;
}

void B::setVal(int val)
{
    *m_p = val;
}
18
Naveen

最近、クラス内にポインターがある場合、Copyコンストラクターを指定する必要があることを発見しました。

それは完全に真実ではありません。クラスにポインタがあり、newを使用してメモリを割り当てる場合は、コピーコンストラクタを考慮する必要があります。また、代入演算子とデストラクタも忘れないでください。 deleteを使用して割り当てられたメモリを削除する必要があります。

Law Of The Big Three と呼ばれています。

例:

  ~Matrix();  //Destructor
  Matrix(const Matrix& m); //Copy constructor
  Matrix& operator= (const Matrix& m); //Assignment operator
9
aJ.

ディープコピーを行う場合は、もちろん値を保持するために新しいメモリも割り当てる必要があります。オリジナルにintへのポインタがあり、コピーで同じポインタ値を使用したくない場合は、intを保持するために新しいメモリを割り当て、そこに値をコピーする必要があります。

あなたの例はあまり明確ではありません、それはあなたのコピーコンストラクタの実装やpointerメンバーがどのように初期化されるかを示していません。

3
unwind

私は最近、クラス内にポインターがある場合、コピーコンストラクターを指定する必要があることを発見しました

多くの場合、それ(および代入演算子)をプライベートとして宣言し、実装しないことによって単に無効にすることをお勧めします。

2

通常の型へのポインタがある場合

A::A(const A& a):
  pointer_( new int( *a.pointer_ ) )
{
}

基本クラスへのポインタがある場合

A::A(const &a ):
  pointer_( a.pointer_->clone() )
{
}

クローンは プロトタイプパターン の実装です

デストラクタでポインタを削除することを忘れないでください

A::~A()
{
    delete pointer_;
}

あなたの例を修正するには

TRY::TRY(TRY const & copyTRY){
    int a = *copyTRY.pointer;
    pointer = new int(a);
}
1
Mykola Golubyev

あなたの問題はここのこの行にあります:

    *pointer = a;

*pointerへのメモリの割り当てを含め、通常、デフォルトのコンストラクタで通常発生することはすべてまだ発生していません。

修正は、整数にメモリを割り当てることです。これにはmalloc and friendsまたはnewを使用できますが、デストラクタを1つだけ取得し、呼び出しが一致する必要があるため、デフォルトのコンストラクタで使用するのと同じメソッドであることを確認してください。

1
Ben Straub

メンバーごとの(浅い)コピーで問題がなければ、何もする必要はありません。ディープコピーが必要な場合は、すべてのメンバーのコピー用に新しいストレージを割り当てる必要があります。

1
Zifre

コピーコンストラクターを作成するときは、すべてのメンバーにメモリを割り当てる必要があります。あなたの場合:

TRY::TRY(TRY const & copyTRY){
    pointer = new int(*(copyTry.pointer));
}

Operator =は多少似ていますが、メモリ割り当てはありません。

TRY& operator=(TRY const& otherTRY){
      this->a  = *(otherTry.pointer)
      return *this
}
0
Tom