11

I am alittle bit confused on topic of allocating objects on heap vs allocating on stack, and when and how delete() should be called.

For example I have class Vector. I would like to make an array of these.

I could either do this

Vector** v = new Vector*[100]; //create an array of 100 pointers to 100 Vector objects

This as I understand would allocate everything (well except pointer addresses) on a heap? So to free memory I would need to:

for (int i = 0; i < 100; ++i)
{
   delete(v[i]);
}
delete(v);

OR just

delete(v);

is enough?

Now another example:

Vector* v = Vector[100];

Whats happening in this case? Where does allocation happen? Heap or stack? Do I still need to call

delete(v);

But this is not all question, sorry for long post..

example:

class Vector
{
  int x, y, z;
}

Vector* v = new Vector();

wheres x, y, z allocated? Heap or stack?

or how about this:

class Vector2
{
   int items[10];
}

Vector2* v2 = new Vector2();

where are items[10] allocated? How do I delete v2? Do i need custom destructor?

Also last but not least how about this one:

class Vector3
{
   int* items;
}

Vector3 v3 = Vector3();

Where is items pointer stored? heap or stack? How do I delete this?

Thanks and sorry for long question. Ive been having trouble with this stuff for long time and couldnt really find any complete explanation on line.

Chebz
  • 1,375
  • 3
  • 14
  • 27
  • 2
    Forget about new/delete you do not need them. Just use a std::vector – Martin York Jul 15 '11 at 22:49
  • sorry dude, this was just an example class I gave to understand memory allocation. This does not have anything to do with real application. I might as well called it MyClass. + even if it were std::Vector is something else, dont confuse the names! – Chebz Jul 16 '11 at 19:52
  • It has nothing to do with the name. It is more to do with the use of `new X[]`. In most situations were you do this you should be using `std::vector` – Martin York Jul 16 '11 at 20:46

4 Answers4

14

I'll start from the beginning...

Vector** v = new Vector*[100];

Allocates an array of 100 pointers to objects of type Vector on the heap It returns one pointer- v - the you can use to keep track of this array of pointers.

Delete this array of 100 points with:

delete[] v;

(Use the delete operator- delete for a single allocated object, delete[] for an array)

Next case (I'm assuming you mean new Vector[100]:

Vector* v = new Vector[100];

You allocated an array of 100 Vectors on the heap and got a pointer to its start location- v. Delete this array with:

delete[] v;

Next...

class Vector
{
  int x, y, z;
}

Vector* v = new Vector();

This allocates an object of class Vector on the heap and gives you a pointer to keep track of it. Because you allocated the entire object on the heap, x, y, and z are all allocated on the heap.

Delete it with:

delete v;


class Vector2
{
   int items[10];
}

Vector2* v2 = new Vector2();

This one is a bit trickier but I'm going to reason it out...

Classes are blueprints. You haven't allocated any memory at all until you instantiate the class somehow, in this case on the heap. Because the class is a blueprint, items could not have been allocated until you created an object of class Vector2 on the heap. I think we can reasonably infer that items is thus allocated on the heap.

Delete v2 with:

delete v2;

And finally:

class Vector3
{
   int* items;
}

Vector3 v3 = Vector3();

You allocated all of class Vector3 on the stack, the pointer inside of it items is also allocated thus. Nothing went on the heap, so don't delete it.

Prime
  • 4,081
  • 9
  • 47
  • 64
  • I think a simple `delete[] v;` might cause some memory leaks (if the allocated pointers end up being used). –  Jul 15 '11 at 22:17
  • 3
    Forget about templates. Your understanding of dynamic memory needs to be worked out correctly before you even start thinking about templates. Templates is a whole sub language (you need to understand the main language first). – Martin York Jul 15 '11 at 23:36
  • @Martin: I didn't want to give the impression of templates in the actual C++ sense of a template (vector, etc.). I was trying to convey the understanding that when a class declaration is made, it serves as a blueprint for future allocations of that class. Also, I think Naumov is using Vector in the sense of an X, Y, Z value (in line with the thinking of a 3D coordinate plane) rather than in the sense of an STL template. They are two different things. – Prime Jul 16 '11 at 02:36
  • @Muggen: He only allocated an array of 100 pointers with his first call. There would only be a memory leak if he actually went on to do something with those pointers, for instance allocate 100 Vector objects with them. He didn't, so a simple delete[] suffices. – Prime Jul 16 '11 at 02:39
  • @dragonwrenn: Overloading the term tempate when talking about C++ is a bad idea. Change your phrase too: `Classes are a blueprints.` – Martin York Jul 16 '11 at 04:03
  • The second case doesn't allocate anything. You cannot call delete[] if there is no new[]. – Bo Persson Jul 16 '11 at 07:49
  • Changed. Thanks for catching that. I think Naumov must have meant new Vector[100]. – Prime Jul 16 '11 at 19:58
10

Lets star off that you probably do not need to dynamically allocate anything.
Either a static array or vector will work much better.

But lets assuming you are doing this as a learning exercise.

1 Allocating an array of pointers

Vector** v = new Vector*[100]; //create an array of 100 pointers to 100 Vector objects
                               //
                               // The above comment is misleading.
                               // The 100 pointers have not been initialized.

This allocated an area of memory that has space for 100 pointers (to Vector (Note they are uninitialized ie each pointer in random)). To delete this you need to do:

delete [] v;

2 Allocating the members of the array

If you allocate each of the members (which you should do if you want to use them:

for (int i = 0; i < 100; ++i)
{
   v[i] = new Vector;
}

// Code

for (int i = 0; i < 100; ++i)
{
   delete v[i];
}

So note that for each call to new there should be a corresponding call to delete.

3 An ERROR

Vector* v = Vector[100];

This is just wrong. If will not compile.

4 Where do members go

Unless the member is a pointer it is inside the object.
If the member is a pointer it must be separately allocated.

class Vector
{
  int x, y, z;
}

Vector* v1 = new Vector();
Vector  v2 = Vector();      // Yes the = Vector() is required

Here v1 points at a dynamically allocated object that contain x/y/z
Here v2 is an object that contain x/y/z

I know people are going to say the = Vector(); is a not needed or a copy construction. Both sort of true but both missing the point. 1) Its a copy construction but the compiler is always smart enough to remove it. 2) It is needed to make it equivalent to the line above. The difference is without it is default-initialized (ie not initialized) with it the members are zero-initialized (because Vector() has only a compiler generated constructor).

So what about array members.
They are no different from other members. Members are ALWAYS allocated inside the object. If the member is a pointer then it is inside the object but what it points at has to be explicitly set.

class Bob
{
    int   dataArray[10];
    int*   dataPtr;
};
Bob  b1 = Bob();
Bob* b2 = new Bob();

b1.dataArray[0] = 1;            // dataArray is inside the object.
                                // b1 is allocated locally

b1.dataPtr      = new int [10]; // dataPtr is inside the object.
                                // But what it points at must be seprotally defined.
                                // Note you must call delete [] for each new []
b1.dataPtr[5] = 2;

b2->dataArray[0] = 1;           // dataArray is inside the object.
                                // b2 is allocated dynamically

b2->dataPtr      = new int [10];// dataPtr is inside the object.
                                // But what it points at must be aseptically defined.
                                // Note you must call delete [] for each new []
b2->dataPtr[5] = 2;
Martin York
  • 257,169
  • 86
  • 333
  • 562
2

General rule:

  • when you use new or new [], you allocate on heap, in other case you allocate on stack.

  • every time you use new you should use delete (explicitly or not)

  • every time you use new[] you should use delete[] (explicitly or not)

The next code is UB since you use one new[] and 101 delete. Use one delete[].

Vector** v = new Vector*[100];
for (int i = 0; i < 100; ++i)
{
   delete(v[i]);
}
delete(v);
Yuras
  • 13,856
  • 1
  • 45
  • 58
  • Undefined behaviour, situation that was not fully specified by language standard, so each language implementation can act as it wants. It can crash, or damage your data, or launch Space Shuttle. – Yuras Jul 16 '11 at 21:32
1
  1. delete [] v; - it's an array notation of delete operator. You have to use it when deleting arrays, instead of deleting each element sequentially.
  2. Vector* v = Vector[100]; just won't compile. Write Vector v[100]; and it will allocate array of vectors on stack. You may not delete it manually.
  3. x, y, z are on the heap as the whole object is on the heap
  4. items[10] is also allocated on the heap as is makes part of the object. To delete it just call delete v2;. You don't need a special destructor unless you allocate anything in constructor.
  5. int* items; is stored on the stack as it's part of the object allocated on stack. You don't have to delete it, it will be deleted automatically when comes out of scope.
RocketR
  • 3,626
  • 2
  • 25
  • 38