简体   繁体   中英

A 'deep copy' constructor in C++

I want to build a copy constructor Pair(const Pair& other) . This takes as its argument a read-only reference to another Pair . It should set up the newly constructed Pair as a "deep copy". But I have no idea on how to set up the integers at these new locations, which should be assigned values according to the integers that the other Pair is pointing to.

class Pair {
public:
  int *pa,*pb;
  Pair(int a, int b);
  Pair(const Pair & other);
  ~Pair();
};

Pair::Pair(int a, int b){
  pa = new int;
  pb = new int;
  *pa = a;
  *pb = b;
}

Pair::Pair(const Pair & other){
  pa = new int;
  pb = new int;
  *pa = *(other.pa);
  *pb = *(other.pb);
}

Pair::~Pair(){
  delete pa;
  delete pb;
}

int main() {
  Pair p(15,16);
  Pair q(p);
  Pair *hp = new Pair(23,42);
  delete hp;

  std::cout << "If this message is printed,"
    << " at least the program hasn't crashed yet!\n"
    << "But you may want to print other diagnostic messages too." << std::endl;
  return 0;
}

Your converting constructor is not assigning values to the int s it allocates, and it is not assigning those pointers to the class members.

Your copy constructor is likewise not assigning the allocated pointers to the class members. It is also not using the * operator correctly when accessing other 's members.

Your destructor needs to delete the class members that the constructors allocated.

And you need to add a copy assignment operator to finish out the Rule of 3 properly.

Try this:

class Pair {
public:
  int *pa,*pb;
  Pair(int a, int b);
  Pair(const Pair & other);
  ~Pair();
  Pair& operator=(const Pair & other);
};

Pair::Pair(int a, int b){
  pa = new int;
  pb = new int;
  *pa = a;
  *pb = b;

  /* alternatively:
  pa = new int(a);
  pb = new int(b);
  */
}

Pair::Pair(const Pair & other){
  pa = new int;
  pb = new int;
  *pa = *(other.pa);
  *pb = *(other.pb);

  /* alternatively:
  pa = new int(*(other.pa));
  pb = new int(*(other.pb));
  */
}

Pair::~Pair(){
  delete pa;
  delete pb;
}

Pair& Pair::operator=(const Pair & other){
  *pa = *(other.pa);
  *pb = *(other.pb);
  return *this;
}

int main() {
  Pair p(15,16);
  Pair q(p);
  Pair *hp = new Pair(23,42);
  p = *hp;
  delete hp;

  std::cout << "If this message is printed,"
    << " at least the program hasn't crashed yet!\n"
    << "But you may want to print other diagnostic messages too." << std::endl;
  return 0;
}

Your first constructor could look like that:

Pair::Pair(int a, int b)
    : pa(new int(a))
    , pb(new int(b))
{
}

And you don't need to write complex code multiple time by forwarding to the first constructor.

Pair::Pair(const Pair & other) 
    : Pair(*other.pa, *other.pb) 
{
}

Another thing is that you must also implement assignment operator. Otherwise, your code would be very error prone if you accidently do an assignment (as you would have a double delete assuming that your destructor is properly implemented.

Having said that, your destructor should be:

Pair::~Pair()
{
    delete pa;
    delete pb;
}

As other have said, it would be simpler to directly use int for members as you would not have to define copy and assignment yourself.

// Inside class declaration
Pair &operator=(const Pair &other);

// With other definitions.
Pair &Pair::operator=(const Pair &other)
{
    *pa = *other.pa;
    *pb = *other.pb;
    return *this;
}

If you really need pointers, then I would recommend you to use std::unique_ptr instead.

In your class the declaration become std::unique_ptr<int> pa; and similar for pb . At that point your destructor become empty. Remaining code could stay the same.

Also it is preferable to avoid making variable member public and even more in a case like this where you have dynamically allocated memory.

You can use custom constructor, copy constructor as below:

 class Pair {
 public:
   int *pa,*pb;
   Pair(int, int);
   Pair(const Pair &);
  ~Pair();
 };

 /*
 * Implement its member functions below.
 */
 Pair::Pair(int a, int b){
  pa = new int;
  pb = new int;
  *pa = a;
  *pb = b;
}

Pair::Pair(const Pair & other){
  pa = new int;
  pb = new int;
  *pa = *(other.pa);
  *pb = *(other.pb);
}

Pair::~Pair(){
  delete pa;
  delete pb;
}

 /* Here is a main() function you can use
  * to check your implementation of the
  * class Pair member functions.
  */

int main() {
  Pair p(15,16);
  Pair q(p);
  Pair *hp = new Pair(23,42);
  delete hp;

  std::cout << "If this message is printed,"
    << " at least the program hasn't crashed yet!\n"
    << "But you may want to print other diagnostic messages too." << std::endl;
  return 0;
}

Your init constructor and copy constructor may have some mistakes.

the init constructor should be:

Pair::Pair(int a, int b){
  pa = new int;
  pb = new int;
  *pa = a;
  *pb = b;
}

And copy constructor should be:

Pair::Pair(const Pair & other){
  pa = new int;
  pb = new int;
  *pa = *(other.pa);
  *pb = *(other.pb);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM