简体   繁体   中英

C++ Copy Constructor - Deep Copy of Pointers Segmentation Fault

I recently began learning C++ via Advanced Computer Science Fundamentals MOOC. We have a challenge that declares in a hidden .h file (cannot change) and we need to code all of the member functions/constructors/destructor initialized in the .h file.

To avoid cheating or anyone doing the work for me, I would just appreciate if anyone can help explain what I am doing wrong and what I am doing to get a segmentation fault. I've searched and searched all deep vs shallow copy guides but can't seem to understand what I am doing wrong with this.

Here is the .h file:

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

Two things to point out from this is that the pa/pb are pointers to ints rather than just ints and that there is no place for an assignment operator even though I read about the "Rule of the Big Three" that explained if I had copy constructor or destructors I should also have assignment operator.

Moving along, I tried many things to get this to work and included tons of diagnostic messages and can see sort of where I am messing up but can't understand why or what I should be doing.

Custom Constructor I think this is okay:

 Pair::Pair (int a,int b) {
      int *pa = new int(a);
      int *pb = new int(b);
      std::cout << "pa points to value : " << *pa <<std::endl;
      std::cout << "pb points to value : " << *pb <<std::endl;
      std::cout << "custom constructor resolved "<<std::endl;
    }

Copy Constructor Please forgive all the comments I was just trying to troubleshoot.

    Pair::Pair(const Pair &obj) {

    int *const * a = &obj.pa;
    int *const * b = &obj.pb;
    int *pa = new int;
    int *pb = new int;
    pa = *a;
    pb = *b;

    std::cout << "obj.pa address is : " << &obj.pa <<std::endl;
    std::cout << "obj.pb address is : " << &obj.pb <<std::endl;
    std::cout << "obj.pa points at : " << obj.pa <<std::endl;
    std::cout << "obj.pb points at : " << obj.pb <<std::endl;

    std::cout << "pa address is : " << &pa <<std::endl;
    std::cout << "pb address is : " << &pb <<std::endl;
    std::cout << "pa is pointing at : " << pa <<std::endl;
    std::cout << "pb is pointing at : " << pb <<std::endl;
    std::cout << "copy constructor called "<<std::endl;
     }

Destructor I think I did okay on this one:

    Pair::~Pair() {
      delete pa; pa = nullptr;
      std::cout << "pa deleted " << std::endl;

      delete pb; pb = nullptr;
      std::cout << "pb deleted " << std::endl;
    }

Main Series of tests

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;
}

Looking at this the program would create a pair p; then create a deep copy pair q; then create a pointer to pair hp that points to a pair 23,42 on the heap; and then deletes pointer to pair hp. Everything seems to compile and run properly except for the copy constructor. The main issue is that &obj.pa seems to be just pulling the address that the pointer *pa of object obj is pointing to rather than retrieving the actual dereferenced value.

For additional information here is the terminal output when executing .main (adding additional commentary):

pa points to value : 15            // pair p.pa correct
pb points to value : 16            // pair p.pb correct
custom constructor resolved        // pair p made
obj.pa address is : 0x7fff1887c780 // address original object pointer pa stored 
obj.pb address is : 0x7fff1887c788 // address original object pointer pb stored
obj.pa points at : 0x2             // address pointer obj pa is directed to (I want the value not this)
obj.pb points at : 0x40102d        // address pointer obj pb is directed to (I wand the value not this)
pa address is : 0x7fff1887c728     // pa address on stack
pb address is : 0x7fff1887c730     // pb address on stack
pa is pointing at : 0x2            // address value copied not address itself
pb is pointing at : 0x40102d       // address value copied not address itself
copy constructor called            // copy constructor runs through albeit incorrect
pa points to value : 23            // hp.pa
pb points to value : 42            // hp.pb
custom constructor resolved        // constructor made on heap from pointer hp
pa deleted deleted original pa     // (made from pointer to pair hp)
pb deleted deleted original pa     // (made from pointer to pair hp)
If this message is printed, at least the program hasn't crashed yet!
But you may want to print other diagnostic messages too.
pa deleted                         // deleted original pa (made from pair p)
pb deleted                         // deleted original pb (made from pair p)

I run through and after all execution get 'Segmentation Fault' which I can't quite understand. And being so early in C++ I am not even confident in my terminology to help my searching ability.

You have two significant errors.

First you are redeclaring your pointers inside your constructors.

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

should be

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

By redeclaring the pointers, you are hiding the pointers in the class that you want to assign to, and instead are assigning to local variables that only exist in your constructor.

Exact same problem in the copy constructor.

Secondly you aren't copying the content of the pointers on the right hand side when you execute the copy constructor. You are copying the pointers themselves.

Its actually much easier than this, just adapt the code from your other constructor.

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

Same code as in the other constructor except we initialise the integers with the values from obj instead of the values from the parameters.

Or if you prefer smaller steps

Pair::Pair(const Pair &obj) {
    int a = *obj.pa;
    int b = *obj.pb;
    pa = new int(a);
    pb = new int(b);

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