21

クラス内にポインターがある場合、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++ でディープ コピー コンストラクターを使用する、もう少しスマートな方法はありませんか?...

4

10 に答える 10

22

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

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

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;
}
于 2009-04-23T13:47:38.300 に答える
10

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

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

それはビッグスリーの法則と呼ばれています。

例:

  ~Matrix();  //Destructor
  Matrix(const Matrix& m); //Copy constructor
  Matrix& operator= (const Matrix& m); //Assignment operator
于 2009-04-23T14:07:46.380 に答える
3

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

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

于 2009-04-23T13:48:08.033 に答える
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);
}
于 2009-04-23T13:46:37.943 に答える
2

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

多くの場合、(および代入演算子) を非公開として宣言し、実装せずに単純に無効にすることをお勧めします。

于 2009-04-23T14:08:10.090 に答える
1

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

于 2009-04-23T13:54:54.710 に答える
1

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

    *pointer = a;

デフォルトのコンストラクターで通常発生するすべてのことはまだ発生していません。これには、 *pointer.

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

于 2009-04-23T13:52:16.087 に答える
0

When writing a Copy Constructor, you should allocate memory for all members. In your case:

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

Operator= is somehow similar, but with no memory allocation.

TRY& operator=(TRY const& otherTRY){
      this->a  = *(otherTry.pointer)
      return *this
}
于 2009-04-23T14:05:27.773 に答える
-1

これはコピーコンストラクターの例です

class Test
{​​​​​​​
private:
    int *s;
    int size;
public:
    Test(int a, int b);
    Test(const Test&t);
    ~Test();
    void setValue(int l);
    void getValues();
}​​​​​​​;


Test::Test(int a, int b)
{​​​​​​​
    s = new int;
    *s = a;
    this->size = b;
}​​​​​​​
Test::Test(const Test&t) {​​​​​​​
    s = new int;
    *s = *(t.s);
    this->size = t.size;
}​​​​​​​
void Test::setValue(int l) {​​​​​​​
    *s = l;
}​​​​​​​
void Test::getValues() {​​​​​​​
    cout << "value of s: " << *s << endl;
    cout << "value of size: " << this->size << endl;
}​​​​​​​


Test::~Test() {​​​​​​​
    cout << "memory de allocated!!!" << endl;
    delete s;
}​​​​​​​
于 2021-06-26T04:06:09.133 に答える
-3

多くの場合、コピーコンストラクターまたは代入演算子を作成する必要がある場合は、何か間違ったことをしています。コピーコンストラクタと代入演算子は、標準ライブラリの実装者に任せてください。すでにコピー可能で割り当て可能な要素のクラスを作成すれば、独自の要素を作成する必要はありません。

たとえば、そのint*メンバーは代わりにstd::vectorである必要があります。

クラスをデフォルトでコピー可能/割り当て可能にすることができない場合は、プライベートコピーコンストラクターと代入演算子を宣言することで、コピー不可/割り当て可能にすることができますが、実装はできません。

上記のいずれも実行可能でない場合にのみ、独自のコピーコンストラクターまたは代入演算子を実装する必要があります。

于 2009-04-23T17:17:29.093 に答える