0
votes

I am trying to implement an operator= in C++ for an object which has as a member a pointer to a user defined type which also has dynamic memory allocated in it.

So given the code below, how would on implement a correct operator= for B? What I am after is how is the dynamic memory in A copied to the new B object?

Any help would be much appreciated.

Thank you

class A
{
  int a;
  int* b;

  public:
    A()
    {
      a = 1;
      b = new int [20];
    }
};  

class B
{
  A* a;

  public:
  B()
  {
    a = new A;
  }
}
2
Implement the copy constructor and destructor first. Worry about the assignment operator after those are implemented. Implementation of the copy constructor and destructor will make the assignment operator trivial.PaulMcKenzie
Following on from what Paul said, see herejohn
To answer your specific question how is the dynamic memory in A copied to the new B object? the answer is, by calling the copy constructor for A. You need destructors, copy constructors and assigment operators for both A and B. Start with A first since it has no dependencies.john
In your objects as shown, it is not even necessary to use pointers or dynamically allocated memory. If you get rid of those, you would not even need to define a copy constructor, destructor, or assignment operator. In other words, the correct answer in your case would be "you don't".Peter

2 Answers

1
votes

For starters you should define at least copy constructor, copy assignment operator and destructor for the class A. Then it is simple to define the copy assignment operator for the class B.

For example

#include <iostream>
#include <algorithm>

class A
{
    static const size_t N = 20;
    int a;
    int* b;

public:
    A()
    {
      a = 1;
      b = new int [N]();
    }

    A( const A &a ) : a( a.a ), b( new int [N] )
    {
        std::copy( a.b, a.b + N, this->b );
    }

    A & operator =( const A &a )
    {
        if ( &a != this )
        {
            this->a = a.a;

            int *p = new int[N];

            std::copy( a.b, a.b + N, p );

            delete [] this->b;
            this->b = p;
        }

        return *this;
    }

    ~A()
    {
        delete []b;
    }
};  

class B
{
  A* a;

  public:
  B() : a( new A )
  {
  }

  // copy constructor

  ~B()
  {
    delete a;
  }

  B & operator =( const B &b )
  {
    if ( this != &b )
    {
        *this->a = *b.a;
    }

    return *this;
  }
};

int main()
{
    B b1;
    B b2;

    b1 = b2;
}

Pay attention to that in the copy assignment operator at first created a new array before deleting the old one. This allows to keep the stable state of the assignable object if an exception will occur.

0
votes

At very first: Have a look at the rule of three, it is an absolute must go in given case. Consider, too, the rule of five, while not mandatory, you'll leave out a great optimisation opportunity...

The destructor would now delete[] the array (leaving this part to you...), a copy constructor would then do exactly that: (deep) copy the data:

A::A(A const& other)
   : a(other.a), b(new int[20]) // assuming you have a fixed size for those arrays;
                                // better: introduce a constant for to avoid magic
                                // numbers in code!
{
    // you created a new array, but yet need to fill it with the others value
    std::copy(other.b, other.b + 20, b);
}

OK, first step. Using the copy and swap idiom, the assignment operator gets pretty simple:

A& operator=(A other) // YES, no reference! This will invoke the copy (or move!)
                      // constructor of your class!
{
    swap(*this, other); // you'll need to implement it yet!
    return *this;
    // at this point, the destructor of other will clean up data that was potentially
    // contained in *this before...
}

Finally the move constructor:

A::A(A&& other)
   : a(0), b(nullptr)
{
    swap(*this, other);
    // again swapping??? well, sure, you want the data from other to be contained
    // in *this, and we want to leave other in some kind of valid state, which the
    // nullptr is fine for (it's fine to delete[] a null pointer, so you don't even
    // need to check in the destructor...) 
}

And now up to you: class B analogously...

Side note: you get away a bit cheaper by use of a smart pointer (std::unique_ptr), it will allow you to default destructor and move constructor + assignment operator, solely copy constructor and assignment operator need to be implemented explicitly (std::unique_ptr is not copiable...).