By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,187 Members | 1,038 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,187 IT Pros & Developers. It's quick & easy.

Virtual Destructors and array of objects

P: n/a
Ok, my question is not about Virtual destructors and why, but more on
the significance.
Generally we have a virtual destructor in the base class ( and
inadvertently in the derived class) so that you can delete a
derived-class object via a base-class pointer...So, the correct
destructor(s) gets invoked(the derived class one in particular) and the
correct amount of memory is also released.

But if the above is true, why isnt it a good practice to allocate an
array of derived objects via base class pointer and then delete them
via this base class pointer using delete[] ptr ?

I am going through the FAQ about placement new and how the whole thing
is implemented so as to keep track of the number of objects and
therefore call each corresponding destructor.

So if deleting derived objects via base pointer works for one object,
then I dont know why it wouldnt work for deleting an array of derived
objects via base pointer.

Maybe I am missing something or maybe my understanding is not
complete...can anyone throw more light on this.

Thanks.

Jul 23 '05 #1
Share this Question
Share on Google+
10 Replies


P: n/a

<am******@gmail.com> skrev i en meddelelse
news:11*********************@g49g2000cwa.googlegro ups.com...
Ok, my question is not about Virtual destructors and why, but more on
the significance.
Generally we have a virtual destructor in the base class ( and
inadvertently in the derived class) so that you can delete a
derived-class object via a base-class pointer...So, the correct
destructor(s) gets invoked(the derived class one in particular) and the
correct amount of memory is also released.

But if the above is true, why isnt it a good practice to allocate an
array of derived objects via base class pointer and then delete them
via this base class pointer using delete[] ptr ?

I am going through the FAQ about placement new and how the whole thing
is implemented so as to keep track of the number of objects and
therefore call each corresponding destructor.

So if deleting derived objects via base pointer works for one object,
then I dont know why it wouldnt work for deleting an array of derived
objects via base pointer.
Because the standard says so.

Maybe I am missing something or maybe my understanding is not
complete...can anyone throw more light on this.

Thanks.


See the thread "virtual destructors" in this group. I have given an
explanation as to why it does not work there.

/Peter
Jul 23 '05 #2

P: n/a
am******@gmail.com wrote:
Ok, my question is not about Virtual destructors and why, but more on
the significance.
Generally we have a virtual destructor in the base class ( and
inadvertently in the derived class) so that you can delete a
derived-class object via a base-class pointer...So, the correct
destructor(s) gets invoked(the derived class one in particular) and the
correct amount of memory is also released.
Right.
But if the above is true, why isnt it a good practice to allocate an
array of derived objects via base class pointer and then delete them
via this base class pointer using delete[] ptr ?
I don't seem to understand the question. An array of derived objects
via base class pointer? Could you illustrate it with some code? Do you
mean

base *array = new derived[10];

? That won't work as soon as you try indexing.
I am going through the FAQ about placement new and how the whole thing
is implemented so as to keep track of the number of objects and
therefore call each corresponding destructor.

So if deleting derived objects via base pointer works for one object,
then I dont know why it wouldnt work for deleting an array of derived
objects via base pointer.
Deleting an array involves the _size_. The size is obtained from the
type of the array element...
Maybe I am missing something or maybe my understanding is not
complete...can anyone throw more light on this.


I guess you need to realize the difference between the 'delete' and
'delete[]'. If you need help, just ask (after you've searched all the
usual places for the explanations).

V
Jul 23 '05 #3

P: n/a
On 7 Jun 2005 13:41:37 -0700, am******@gmail.com wrote:

[snip]
why isnt it a good practice to allocate an
array of derived objects via base class pointer and then delete them
via this base class pointer using delete[] ptr ?


You can allocate an array of base class pointers and use them
polymorphically (once you hae allocated their respective objects and
assigned their respective pointers to the array elements, that is).
But delete[] will only delete the storage for the pointers themselves,
not what they point to!

As others have pointed out (and this is, or should be, a FAQ) one must
never allocate an array of *objects* polymorphically because each
array element must have the same size.

--
Bob Hairgrove
No**********@Home.com
Jul 23 '05 #4

P: n/a
> But if the above is true, why isnt it a good practice to allocate an
array of derived objects via base class pointer and then delete them
via this base class pointer using delete[] ptr ? I

don't seem to understand the question. An array of derived objects
via base class pointer? Could you illustrate it with some code? Do
you
mean

base *array = new derived[10];
Lets for simplicity assume that I hold this allocated ptr(via new or clone) via a smart ptr that holds the base type. Whenever I want to process something, I cast it to the type of the correct object and use it. However when the smart ptr goes out of existence it would just do a
delete[] ptr.
? That won't work as soon as you try indexing.this I agree and as I said while processing i cast it to the right
I am going through the FAQ about placement new and how the whole thing
is implemented so as to keep track of the number of objects and
therefore call each corresponding destructor. So if deleting derived objects via base pointer works for one object,
then I dont know why it wouldnt work for deleting an array of derived
objects via base pointer.

Deleting an array involves the _size_. The size is obtained from the
type of the array element...
thats my question. if it knows how to delete one object and it deletes them correctly, then why cant it interpolate over n number of objects.
so lets say
base* ptr = new derived;
delete ptr; //here it does the right thing if the destructor is
declared virtual....it calls the right destrcutor and frees the right
amount of memory.

now when you do
delete[] ptr; //from what I understand, it has to get the ACTUAL size
of the underlying object.

Wouldnt this be analogous to say something like a dynamic_cast
operation from a base class pointer to a derived class pointer. Even in
this case, you need to check the underlying pointer( which is what
operator delete or dynamic_cast does) and just interploate it over n
number of objects( as has been demonstarted in the FAQ via placement
http://www.parashift.com/c++-faq-lit....html#faq-38.8)
Maybe I am missing something or maybe my understanding is not
complete...can anyone throw more light on this.

I guess you need to realize the difference between the 'delete' and
'delete[]'. If you need help, just ask (after you've searched all the
usual places for the explanations).
I probably do understand them as much required within the current context. Thanks.


V

Jul 23 '05 #5

P: n/a
I am actually allocating all objects of the same size, the derived
class. They arent of different sizes(or different types of derived
classes)

Jul 23 '05 #6

P: n/a

<am******@gmail.com> wrote in message
news:11*********************@o13g2000cwo.googlegro ups.com...

thats my question. if it knows how to delete one object and it deletes
them correctly, then why cant it interpolate over n number of objects.


The rules are simply different for arrays. A base class pointer can be used
polymorphically. But a pointer to an array of objects cannot.

If you want polymorphic behavior when using an array, then make it an array
of base class pointers, and allocate (and later delete) each pointer in the
array individually. (Even better, use a vector of base class pointers!)

There are plenty of explanations about this behavior in this newsgroup and
the moderated one. Try a google search for something like "delete array
derived class objects".

-Howard
Jul 23 '05 #7

P: n/a

<am******@gmail.com> wrote in message
news:11*********************@g49g2000cwa.googlegro ups.com...
Ok, my question is not about Virtual destructors and why, but more on
the significance.
Generally we have a virtual destructor in the base class ( and
inadvertently in the derived class) so that you can delete a
derived-class object via a base-class pointer...So, the correct
destructor(s) gets invoked(the derived class one in particular) and the
correct amount of memory is also released.

But if the above is true, why isnt it a good practice to allocate an
array of derived objects via base class pointer and then delete them
via this base class pointer using delete[] ptr ?
Because the array is created at compile-time. You need a container that
supports run-time compilation. In effect, the goal is not to delete the
container, but rather, you want to delete the objects within (or in your
case, the objects pointed to). Its the objects, not the container of
pointers, that are polymorphic.

I am going through the FAQ about placement new and how the whole thing
is implemented so as to keep track of the number of objects and
therefore call each corresponding destructor.

So if deleting derived objects via base pointer works for one object,
then I dont know why it wouldnt work for deleting an array of derived
objects via base pointer.
There is a huge difference since a base pointer to an object is potentially
a derivative. An array knows no derivatives (its a compile time creature).
Thats why vectors, deques, stacks, list, map, sets where created. So that
the object, not the container, has invocable and callable behaviours.

Maybe I am missing something or maybe my understanding is not
complete...can anyone throw more light on this.


You are on the right track.

Jul 23 '05 #8

P: n/a

<am******@gmail.com> wrote in message
news:11**********************@g47g2000cwa.googlegr oups.com...
I am actually allocating all objects of the same size, the derived
class. They arent of different sizes(or different types of derived
classes)


No you are not, you are allocating objects but storing pointers. the array
is not an array of objects. If you delete the array, you only delete the
object's pointers. In fact, the same goes for any type of container:

#include <iostream>
#include <vector>

class Base
{
int m_b;
public:
Base(int n) : m_b(n) { std::cout << "Base ctor\n"; }
virtual ~Base() { std::cout << "\nBase d~tor"; }
};

class Derived : public Base
{
public:
Derived(int n) : Base(n) { std::cout << "Derived ctor\n"; }
~Derived() { std::cout << "\nDerived d~tor"; }
};
int main(int argc, char* argv[])
{
std::vector< Base* > v_ptr_bases;

for (int i = 0; i < 5; ++i)
{
v_ptr_bases.push_back(new Derived(i));
}

// v_ptr_bases.clear(); // no way, those are pointers

typedef std::vector< Base* >::iterator VIter;
for (VIter it = v_ptr_bases.begin(); it != v_ptr_bases.end(); ++it)
{
delete *it;
}

return 0;
}

/*
Base ctor
Derived ctor
Base ctor
Derived ctor
Base ctor
Derived ctor
Base ctor
Derived ctor
Base ctor
Derived ctor

Derived d~tor
Base d~tor
Derived d~tor
Base d~tor
Derived d~tor
Base d~tor
Derived d~tor
Base d~tor
Derived d~tor
Base d~tor
*/

There is no doubt that an auto pointer saves the day since manual
deallocation is no longer needed. But its still relevant to acknowledge that
a container of pointers is not a container of objects.

Jul 23 '05 #9

P: n/a
Peter Julian wrote:
There is no doubt that an auto pointer saves the day since manual
deallocation is no longer needed. But its still relevant to acknowledge that
a container of pointers is not a container of objects.


I'm not sure if you were suggesting this or not, but it is worth noting
that std::auto_ptr does NOT meet the requirements to be stored in any of
the standard containers.
Jul 23 '05 #10

P: n/a
Me
The important thing to know is that C++ is a value based language, it
doesn't behave like other languages where you can do this (all their
objects are really pointers to objects, they just hide that from you):

struct A { int a; };

struct B : A { float f; };

vector<A> v;
B b;

//vector<A>::push_back(const A &);
v.push_back(b);

^-- What happens here is called slicing. In the call to push_back, b
gets downcasted to an A object and just copies the A object of b over
to the end of the vector. Slicing is considered to be a bad thing in
all but a few cases as you lose certain information. Agree with me so
far?

A a;
//A::operator=(const A &);
a = b;

^-- Slicing also happens with regular objects because that's what the
regular assignment operator is expected to look like.

A arr[10];
//arr's index operator returns an A &, this calls the assignment
operator above
arr[2] = b;

A *narr = new A[10];
//ditto
narr[2] = b;

^-- Slicing also happens when using plain arrays of regular objects. So
you can see there is no way to store a full B into an array of A,
therefore an array of type A can only hold objects of type A (or a
const/volatile compatible A).

The standard doesn't want to bend over backwards to handle the rare
case of where you write a correct assignment operator that somehow
handles slicing because doing that requires the base and derived class
to be the same size (rare in general and not guaranteed) and in your
case, involves a memcpy to copy the vtable over (which is undefined and
assumes your implementation even uses vtables).

Not all is lost, this code is correct, see if you can figure out why:

vector<A*> v2();

// this is ok
v2.push_back(new B);
delete v2[0]; // call's B's destructor

// this is ok
A **arr2 = new A*[1];
arr2[0] = new B;
delete arr2[0] // calls B's destructor
delete [] arr2;

Jul 23 '05 #11

This discussion thread is closed

Replies have been disabled for this discussion.