Solved

Why does the following code act the way it does?

Posted on 2000-03-22
6
207 Views
Last Modified: 2010-04-10
//
//  The mystery is why does b get deleted?
//  It seems to have been tarred by its association with a.
//
//
#include <list>
#include <assert.h>
#include <string>

class Contig {

 public:
  list<Contig> left;
  list<Contig> right;
  char *id; // This is just for debug

  void AddLeft( Contig &c ) ;

  Contig( );
  ~Contig( );
};


Contig::Contig() {
  id = (char *) NULL ;
}

Contig::~Contig() {
  if ( id ) cerr << " id = " << id << endl ;
  cerr << " Here we are in ~Contig" << endl ;
  if ( id ) delete [] id;
}

void Contig::AddLeft(  Contig &c ) {

  left.push_front( c ) ;
  c.right.push_front( *this ) ;
}

//
//  My goal is to set up a simple graph structure,
//  each element (or member of the class Contig)
//  may have Contigs on the left and on the right.
//  The structure should be symmetrical (or doubly-linked)
//  in that if a is on the right of b, then b is on the
//  left of a.  
//
//  b - a
//
//  In other words, b is to the left a and a is to the right
//  of b.
//
main(){

  Contig *a = new Contig;
  a->id = "A";
  Contig *b = new Contig;
  b->id = "B";

  a->AddLeft(*b);    // In essence, this sets a->left = b and a->right = a
                     // If I comment out this line, b does not get deleted

  delete a;          // This line deletes both a and b - Why?
  cerr << " We are at the bottom now " << endl ;
}

<
0
Comment
Question by:klopter
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
6 Comments
 
LVL 7

Expert Comment

by:KangaRoo
ID: 2645436
I suspect the output may be deceiving you. The problem I spot is with deleting id. Basically the flow is

id = "A"; // in main

delete [] id; // in ~Contig

You're deleting something that must not be deleted. After that, anything may happen (output can not be trusted)
0
 

Expert Comment

by:mgdPaul
ID: 2645738
I might say the same as Kangaroo.

a is calling it's function and passes b. In the function you use b to push a to the front, bnut only a pointer to it. Then you delete a, and so b points to nothing.

If I understand push_front right, that is.
0
 
LVL 1

Accepted Solution

by:
tomkeane earned 100 total points
ID: 2645974
It looks like you want to change your class definition a bit so that the objects are keeping a list of pointers to their adjacecent objects.  Currently you are storing a list of copies of the adjacent objects.

Change:
  list<Contig> left;
  list<Contig> right;
to:
  list<Contig*> left;
  list<Contig*> right;
 
and change AddLeft() to :

void AddLeft( Contig * c )
{
  left.push_front( c );
  c.right.push_front( this );
}

0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 5

Expert Comment

by:pitonyak
ID: 2646890

Why do you believe that b is being deleted? It is not.

To see this, print the address of the object as it is being destroyed. Also, print the value of  a and b (note that this means print the value of the pointers, not *a and *b).

Ultimately, you are storing a copy of *a and a copy of *b in the lists.

Some notes:
1) The destructor contains the code: delete [] id (as mentioned by KangaRoo). If you did not dynamically allocate this memory then do not do this. You can avoid this problem by creating a set function.....
void Contig::setId(const char* c) {
    delete[] id;
    id = 0;
    if (c != 0) {
        id = new char[strlen(c)];
        strcpy(id, c);
    }
}
 


2) Remember that I said you storing a copy of *b, not b itself. Well, this means that the default copy constructor is being used to make this copy. You can see this by implementing your own copy constructor, which you should do anyway. This way, you can safely copy pointers.

const Contig& Contig::copy(Contig& x) {
  if (this != &x) {
    setId(x.id);  // this uses the safe version above.
    left = x.left;
    right = x.right;
  }
  cout << "I am in the copy constructor" << endl;
  return *this;
}

Now, when you delete a, the destructor is called on a->left and a->right. This contains a copy of both *a and *b so I would expect to see the destructor called for an "A" and a "B". Of course when this happens now you are deleting memory that was never allocated which is grounds for instant failure.

I am rambling.... so ttfn

Andy
0
 

Expert Comment

by:harish791
ID: 2647786
It could be that when ~Contig is called, the destructor for the list members(left and right ) is getting called. if the list's destructor deletes elements in the list then b would also get deleted since it is in the left. note that in function addLeft what went in was reference to b.
0
 

Author Comment

by:klopter
ID: 2649536
Yes. Yes. Yes.  You nailed by mistake.

Thanks,

  Ken
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Create string splitting user defined function in C++ 23 356
Arduino EDI - Programming language 3 127
max float value 3 73
Finding Divisors 5 60
What is C++ STL?: STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector. …
  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.

738 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question