Exception and derived destructor

M

Miri

Hi.

I have the following program:

class Papa
{
public:
Papa() {cout<<"Papa "<<endl;}
~Papa() { cout<<"~Papa "<<endl;}
};

class Son : public Papa
{
public:
Son() { m_pNumber=new int[100]; cout<<"Son "<<endl;}
~Son() { cout<<"~Son "<<endl;delete[] m_pNumber; }
private:
int* m_pNumber;
};

void main()
{
try{
Papa* p = new Son;

Son* a = new Son;
Son* b = a;

delete a;
delete b;
}
catch(...){
cout<<"Ooooooooops..."<<endl;
}
}

It is obvious that we get run time error when doing "delete b" since
we already deleted m_pNumber.

Why do we continue to Papa's destructor as well?

Thanks.
 
R

Rolf Magnus

Miri said:
Hi.

I have the following program:

class Papa
{
public:
Papa() {cout<<"Papa "<<endl;}
~Papa() { cout<<"~Papa "<<endl;}
};

class Son : public Papa
{
public:
Son() { m_pNumber=new int[100]; cout<<"Son "<<endl;}
~Son() { cout<<"~Son "<<endl;delete[] m_pNumber; }
private:
int* m_pNumber;
};

void main()

main() must return int.
{
try{
Papa* p = new Son;

Son* a = new Son;
Son* b = a;

delete a;
delete b;
}
catch(...){
cout<<"Ooooooooops..."<<endl;
}
}

It is obvious that we get run time error when doing "delete b" since
we already deleted m_pNumber.

That's not the reason, at least not the only one. You already deleted
the whole object. So b doesn't point to an object anymore. It points to
memory that doesn't belong to your program, and you are not allowed to
use delete on such a pointer.
Why do we continue to Papa's destructor as well?

What do you mean?
 
R

Ron Natalie

Miri said:
It is obvious that we get run time error when doing "delete b" since
we already deleted m_pNumber.

Why do we continue to Papa's destructor as well?

When you invoke delete on b, you've now deleted the same value
twice. This is undefined behavior. What happens after that is
unpredictable (including any behavior of m_pNumber).

Further, while you don't actually do it, you have some other bugs
lurking.

Papa*p = new Son;

Assigns a pointer to a derived class (Son) object to the base class (Papa)
pointer. If you were to do
delete p;

You would have undefined behavior as Papa's destructor is not virtual.

Second, I think you may be confusing copying pointers and copying the
pointed to objects.

Son* b = a;
initializes the pointer a to the pointer b, it doesn't copy the objects.

If you were to do this with the objects:
Son b = *a;
or
Son* b = new Son(a)

you would have problems as you do not have a copy constructor that deals
with m_pNumber sensibly. The "rule of 3" says that if you write a destructor,
a copy constructor, or a copy-assignment operator, you probably need all
three.
 
A

Andrey Tarasevich

Miri said:
class Papa
{
public:
Papa() {cout<<"Papa "<<endl;}
~Papa() { cout<<"~Papa "<<endl;}
};

class Son : public Papa
{
public:
Son() { m_pNumber=new int[100]; cout<<"Son "<<endl;}
~Son() { cout<<"~Son "<<endl;delete[] m_pNumber; }
private:
int* m_pNumber;
};

void main()
{
try{
Papa* p = new Son;

Son* a = new Son;
Son* b = a;

delete a;
delete b;
}
catch(...){
cout<<"Ooooooooops..."<<endl;
}
}

It is obvious that we get run time error when doing "delete b" since
we already deleted m_pNumber.

No, we don't get run time error. We get undefined behavior as a result
of an attempt to delete the same object twice. Anything can happen.
 
S

Shane Beasley

class Papa
{
public:
Papa() {cout<<"Papa "<<endl;}
~Papa() { cout<<"~Papa "<<endl;}
};

class Son : public Papa
{
public:
Son() { m_pNumber=new int[100]; cout<<"Son "<<endl;}
~Son() { cout<<"~Son "<<endl;delete[] m_pNumber; }
private:
int* m_pNumber;
};

void main()

ISO C++ requires that main return int (even if you don't want to
return a value).
{
try{
Papa* p = new Son;

Son* a = new Son;
Son* b = a;

delete a;
delete b;
}
catch(...){
cout<<"Ooooooooops..."<<endl;
}
}

It is obvious that we get run time error when doing "delete b" since

Why do we continue to Papa's destructor as well?

Deleting anything twice elicits undefined behavior, which could mean
any behavior at all. If you're lucky, the program will crash. If
you're not, your program may behave as if nothing happened (as is the
case here), or it may behave badly.

Furthermore, the operators delete and delete[] are not allowed to
throw an exception. If one diagnoses an error, beyond outputting an
error message, all it can do is ignore the error or abort the program.
Your implementation chose to ignore it.

The solution in your case is not to allow two pointers which might
share ownership of an object. My personal rule, whenever possible, is
to use "smart pointers" to manage single objects and std::vector to
manage arrays. That way, I don't actually delete anything myself, so
it's difficult to delete things too many -- or too few -- times.

- Shane
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,141
Messages
2,570,817
Members
47,362
Latest member
ChandaWagn

Latest Threads

Top