Sebastian Zander
Sebastian Zander

Reputation: 347

Constructors, destructors and pointers (and vectors and arrays and delete and that)

Funky title, but honestly I couldn't think of anyone better, sorry :(

While experimenting with pointers I came across this and I need help understanding it. Basically, I create a vector of a pointer to an object. When deleting the pointer that's in the vector, I expect the original ovject to be deleted as well. They are one and the same no?

Here's what I think I do in the code that follows I create a dynamically allocated array, I then put the pointer to half of the elements of the array in a vector of pointers. Each step of the way every object of the class testDestructor knows which 'order' it was created in, they all get assigned an incrementing number via a static integer.

I then pop_back and delete all the pointers in the vector. I only use pop_back because I wanted to see if they get deleted by the vector class, apperantly they don't, but idk if I'm missing something there. The important bit is I delete it.

Now, what I expect to happen is that this deletes the corresponding elements of the array as well. This is what SHOULD happen, because the vector and the array element point to the same place in the memory. ie, the destructor should get called.

So when I then delete the array, I expect that either only 5 of the elements get deleted, or a run-time error occurs (I've had this happen before when I try deleting pointers that already are deleted, but that might have been a different scenario idk). Namely, I expect that only the destructor should only be called five times.

HOWEVER, that's not what happens. The constructor gets called 10 times but the destructor gets called 15 times. What am I missing? Am I missing a constructor (I only know about default constructors and copy constructors, are there more), or is it something else? Because, in my mind, when the destructor is gone the object is gone.

Sorry if it's too much code:

testDestructor.h:

#ifndef TESTDESTRUCTOR_H
#define TESTDESTRUCTOR_H

class testDestructor
{
public:
   testDestructor();
   testDestructor(const testDestructor &);
   ~testDestructor();

   static int maxTest;
   int test;
};

#endif

testDestructor.cpp:

#include "testDestructor.h"
#include <iostream>

using namespace std;

int testDestructor::maxTest = 0;

testDestructor::testDestructor()
{
   test = maxTest++;
   cout << "testDestructor nr " << test << " created successfully\n";
}

testDestructor::testDestructor(const testDestructor &destructorToCopy)
{
   test = maxTest++;
   cout<< "testDestructor nr " << test << " created successfully (using the copy constructor\n";
}
testDestructor::~testDestructor()
{
  //maxTest--;
   cout << "testDestructor " << test << " destroyed successfully\n";
}

main.cpp:

#include <iostream>
#include "testDestructor.h"
#include <vector>
using namespace std;

int main()
{
   cout << "   creating pointer array:\n\n";
   testDestructor *testPtr = new testDestructor[10];

   cout << "   intitiating vector\n\n";
   vector<testDestructor*> testVct;


   for (int i = 0; i < 5; i++)
   {

      cout << "   pushing back vector " << i << ":\n";
      testVct.push_back(testPtr + i);
      cout << "testDestructor " << testVct[i]->test << " pushed back\n";
   }
   cout << "\n";

   for (int i = 4; i >= 0; i--)
   {
      cout << "   popping back vector " << i << ":\n";
      cout << "testDestructor " << testVct[i]->test << " popped back\n";

      delete testVct[i];
      testVct.pop_back();

   }
   cout << "\n";

   cout << "   deleting pointer array\n\n";
   delete [] testPtr;
}

Upvotes: 0

Views: 1545

Answers (5)

gaoxinbo
gaoxinbo

Reputation: 164

First

In my test, this program will core dump at 'delete testVct[i];'

My g++ version is 4.1.6

Maybe you can init testPtr:

testDestructor *testPtr[10];
for(int i=0;i<10;i++)
    testPtr[i] = new testDestructor;

Second

you delete a pointer twice 1) delete testVct[i]; 2) delete [] testPtr;

Upvotes: 0

Code-Apprentice
Code-Apprentice

Reputation: 83557

First of all, let's look at your variable declarations:

testDestructor *testPtr = new testDestructor[10];
vector<testDestructor*> testVct;

This says that testPtr is a pointer to an object of type testDestructor and testVct is a vector of pointers to objects of type testDestructor.

In addition, you allocate an array of testDestructor objects with the new operator and assign the address of the first element in testPtr. Now testPtr can be used as an array to testDestructor objects.

Note that you have not allocated memory for any individual testDestructor objects. This means that you delete any pointers to the objects in the array will result in undefined behavior. On the other hand, using delete[] on testPtr to deallocate the array is permissible.

The general rule here is that every delete or delete[] must have a matching new or new[] and vice versa.

Upvotes: 0

Roddy
Roddy

Reputation: 68053

When deleting the pointer that's in the vector, I expect the original ovject to be deleted as well. They are one and the same no?

No, they're not the same, and your terminology "deleting the pointer" implies you need to go and re-read some basic stuff about pointers in C++.

new creates things, and returns a pointer to what it creates. delete destroys things and is passed a pointer to the thing to destroy. The pointer is unchanged - it just doesn't point anywhere useful following a delete.

What you're trying to do is delete individual objects in an array of objects created with new[]. That simply cannot be done. You can only delete the whole lot with delete[]. If you want to have individually deleteable objects, use a std::vector<TestDestructor>.

Upvotes: 2

James
James

Reputation: 9278

operator delete[] will call the destructors of the items in the array before it deletes the array itself. If you wish to delete some of the items in the array manually you need to set its array index value to NULL afterwards. Calling the destructor twice on the same object is undefined behaviour and will hopefully end badly for you.

Upvotes: 1

krlmlr
krlmlr

Reputation: 25464

The issue here is that the first five instances of testDestructor are deleted twice: Once by delete testVct[i] and another time by delete [] testPtr;.

The first delete is wrong.

The objects are owned by testVct and thus their destruction may be carried out only through delete[]ion of testVct. You can delete individual objects only if they are allocated by new.

Upvotes: 1

Related Questions