I have an abstract Base class and Derived class.
int main ()
{
Base *arrayPtr[3];
for (int i = 0; i < 3; i++)
{
arrayPtr[i] = new Derived();
}
//some functions here
delete[] arrayPtr;
return 0;
}
I'm not sure how to use the delete operator. If I delete array of base class pointers as shown above, will this call derived class objects destructors and clean the memory?
You have to iterate over the elements of your array, delete each of them. Then call delete [] on the array if it has been allocated dynamically using new[].
In your sample code, the array is allocated on the stack so you must not call delete [] on it.
Also make sure your Base class has a virtual destructor.
Reference: When should my destructor be virtual.
No, you have to explicitly delete each item in the array:
for (int i = 0; i < 3; ++i)
{
delete arrayPtr[i];
}
You should instead do:
for ( int = i; i < 3; i++ )
{
delete arrayPtr[i];
}
And you shouldn't do delete[] arrayPtr; as you're trying to free/delete a stack allocated arrayPtr.
Another thing to consider is using a std::vector of pointers instead of an array. And if you're using a compiler that implements TR1, you could also use a std::vector of std::tr1::shared_ptr instead of raw pointers, and than you wouldn't need to worry about deleting those objects yourself.
Example:
{
std::vector< std::tr1::shared_ptr<Base> > objects;
for (int i=0; i < 3; ++i)
{
objects.push_back(std::tr1::shared_ptr<Base>(new Derived()));
}
} // here, once "objects" exit scope, all of your Derived objects are nicely deleted
You have to delete the members of the array individually. You must also make sure that your base class has a virtual destructor. You might also want to consider making it an array (or better still a std::vector) of smart pointers, such as boost::shared_ptr.
No, you can not do that. As others suggested you have to go through each item and delete it. It's a very simple rule to remember. If you allocated using new then use delete, and if you had used new[] then use delete[]
Notice what's absent:
int main() {
boost::ptr_vector<Base> v;
for (int i = 0; i < 3; i++) v.push_back(new Derived());
// some functions here, using v[0] through v[2]
}
Check Boost's pointer containers out.
Operator delete must match operator new on that pointer, if it was allocated with new[], you must call delete[] and vice versa;
int* pInt = new int;
delete pInt; OK
delete [] pInt; WRONG
int[] pIntArr = new int[3];
delete [] pIntArr; OK
delete pIntArr; WRONG
In your case there is something else wrong - you are trying to delete that was allocated on the stack. That wouldn't work.
You must delete each pointer individually in this particular case.
What you have there is undefined behaviour -- a bug. Each call to new needs to be matched with a delete; each call to new[] needs to be matched with a delete[]. The two are separate and can't be mixed.
In the code you posted, you have an array of pointers to Base allocated on the stack. You're then calling delete[] on an array allocated on the stack -- you can't do that. You can only delete[] an array allocated on the heap with new[].
You need a call to delete for each element allocated with new -- or preferably, look into using a container class, such as std::vector, instead of using an array.
Make sure Base has a virtual destructor. Then like fretje outlined, delete each element in the array, then delete the array.
You should be using std::vector for the array. That said, you should really be using a container made for this sort of thing. (So you don't accidentally fail to delete all the elements, which will definitely be the case if an exception gets thrown!) Boost has such a library.
You're mixing paradigms -- The array delete operator is designed to free memory allocated by the array new operator, but you're allocating your array on the stack as an array of pointers and then allocating an object for each array member. In your code, you need to iterate through the array.
To use the array new operator, you'd declare like this:
Base *array;
array = new Base[3];
/* do stuff */
delete[] array;
This allocates a contiguous memory area for the three objects -- note that you've got an array of Base objects, not an array of pointers to Base objects.
No, this doesn't quite do what you want.
There are two points to watch out for here:
The syntax delete[] arrayPtr is used if you dynamically allocate the array, like this:
arrayPtr = new (Base *)[mylength];
In your case, however, you have a statically allocated array, so there is no need to delete it. You do, however, need to delete the individual elements in the array:
for ( int = i; i < 3; i++ )
delete arrayPtr[i];
The second point you need to take care of is to make the destructor of the class Base virtual:
class Base
{
virtual ~Base();
/* ... */
};
This ensures that when you call delete on a Base * that is actually pointing to a Derived, the destructor of Derived is called, not just the destructor of Base.
Related
I write a class vector whose member is a dynamically allocated array
template <typename T> struct vector{
T* elem;int capacity;
/*
*capacity is the size of array, not number of elements in the array .
*the default capacity is 3.
*/
vector(int c=3,T e=0){ /* initializing all elements as e */
T* elem=new T[capacity = c];
for(int i=0;i<capacity;i++){
elem[i]=e;
}
}
~vector(){
delete[] elem;
}
};
Now this is the point, regarding the destructor of vector. If the elements in the member elem is also dynamically allocated object obj, and this object also has its own destructor
int main(){
vector<obj*> vec;
vec.elem[0] = new obj(parameter)
vec.elem[1] = new obj(parameter)
vec.elem[2] = new obj(parameter)
...
}
Is it necessary to delete all the objects in the destructor of vector? like this
~vector(){
for(int i=0;i<capacity;i++){
delete elem[i];
}
delete[] elem;
}
Or I should only delete[] elem and the destructor of obj will finish the rest of work?
Is it necessary to delete all the objects in the destructor of vector? like this
Technically yes but what if you want a vector of pointers that does not represent ownership? You could easily end up either double-deleting an object, or trying to delete a stack-based object:
obj obj_a;
obj* obj_b = new obj;
vector<obj*> obj_ptrs;
obj_ptrs.elem[0] = &obj_a;
obj_ptrs.elem[1] = &obj_a;
obj_ptrs.elem[2] = obj_b;
delete obj_b;
Whether the pointed objects need to be deleted with the vector is none of the vector's business.
The cleanest way to address that is to use std::unique_ptr, which is an object type that holds a pointer and deletes it when it gets destroyed:
#include <memory>
template <typename T> struct vector {
// ...
~vector() {
// The vector is only responsible for deleting the array.
delete[] elem;
}
};
// ...
void foo() {
vector<std::unique_ptr<obj>> obj_ptrs;
obj_ptrs.elem[0] = std::make_unique<obj>();
obj_ptrs.elem[1] = std::make_unique<obj>();
obj_ptrs.elem[2] = std::make_unique<obj>();
obj stack_obj;
vector<obj*> obj_no_own_ptrs;
obj_no_own_ptrs.elem[0] = obj_ptrs.elem[0].get();
obj_no_own_ptrs.elem[1] = obj_ptrs.elem[0].get();
obj_no_own_ptrs.elem[2] = &stack_obj;
// Everything gets deleted
// No double-delete concern
}
In general, when you call delete in an object first it calls the destructor of the class, and second deallocate the memory where the object was allocated.
So, yes. If you create a class call vector it is necessary that you call delete if elem was dynamically allocated before with new.
New always have to be paired with delete. The standard approach was to, e.g. place the new in the constructor, and the delete in the destructor of a class.
In your case, in your class you are dynamically allocating space for other class, that happens to be also a dynamically allocated pointer.
first_object->second_object->third_object...
In this case first_object contain a dynamically allocated vector to second_object. second_object of course can contain more dynamically allocated memory.
In the destructor of your first_object, you delete the second_object so you call the destructor of the second object and deallocate its memory. The call to the destructor of the second_object should delete the third object, so its memory is also deallocated.
If you allocate memory and don't deallocate it, you start to mess the memory because you are fragmenting it. If you call delete without new, or in a object that has been already deleted there will be a segfault. It is always a good idea to place news in constructor and delete in destructors.
Nowadays you also can use shared_ptr or unique_ptr. They will automatically delete its content when they go out scope.
In particular shared_ptr will delete its content when the last pointer pointing to one resource goes out scope
unique_ptr will delete its content when it goes out of scope, since by definition forbid more than one pointer pointing to its content.
{
std::shared_ptr foo = std::make_shared();
std::shared_ptr foo2(new Foo());
}
Both shared pointers will delete its content automatically when they will go out of scope. The first option is preferred and more efficient (make_shared better than call the constructor with new). You could also use unique_ptr that are similar in characteristics to shared_ptr they don't allow more than one pointer pointing to the same resource.
I think you can read about smart pointers and about RAII and it will help you with this
I have a base class and several derived classes. Before I used one container to manage an object but now I have can have several differnt types of students in this case, meaning that I have decided to use base class pointer to manage it. However I am not sure how I can work on the object outside the function that created it. Below is what I have done before to manage objects. Is there something similar to manage containers with base class pointers?
pointer = new SchoolChild[NoOfChildren];//creates pointer that free up space on memory
for (int i = 0; i < NoOfChildren; i++)
{
pointer[i].display();
}
Typically you would move from managing an array of values to an array of pointers:
// from this (pointer to SchoolChild)
SchoolChild* children = new SchoolChild[NoOfChildren];
children[0].name = "name";
// to this (pointer to SchoolChild pointer)
SchoolChild** children = new SchoolChild*[NoOfChildren];
children[0] = new SchoolChild; // allocate each element
children[0]->name = "name";
You also have more deleting to do, needing to delete every element of the array as well as the array itself.
for(int i = 0; i < NoOfChildren; ++i)
delete children[i]; // delete each element
delete[] children; // delete[] the array itself
Better to use containers and smart pointers to manage all that for you:
std::vector<std::unique_ptr<SchoolChild>> children(NoOfChildren);
children[0]->name = "name";
There is no need to delete anything here because the std::unique_ptrs will delete the contained SchoolChild objects and the std::vector will delete the std::unique_ptr elements.
I have
int * array=new int[2];
and I would like to free the memory of the last element, thus reducing the allocated memory to only 1 element. I tried to call
delete array+1;
but it gives error
*** glibc detected *** skuska:
free(): invalid pointer: 0x000000000065a020 *
Can this be done in C++03 without explicit reallocation?
Note: If I wanted to use a class instead a primitive datatype (like int), how can I free the memory so that the destructor of the class is called too?
Note2: I am trying to implement vector::pop_back
Don't use new[] expression for this. That's not how vector works. What you do is allocate a chunk of raw memory. You could use malloc for this, or you could use operator new, which is different from the new expression. This is essentially what the reserve() member function of std::vector does, assuming you've used the default allocator. It doesn't create any actual objects the way the new[] expression does.
When you want to construct an element, you use placement new, passing it a location somewhere in the raw memory you've allocated. When you want to destoy an element, you call its destructor directly. When you are done, instead of using the delete[] expression, you use operator delete if you used operator new, or you use free() if you used malloc.
Here's an example creating 10 objects, and destoying them in reverse order. I could destroy them in any order, but this is how you would do it in a vector implementation.
int main()
{
void * storage = malloc(sizeof(MyClass) * 10);
for (int i=0; i<10; ++i)
{
// this is placement new
new ((MyClass*)storage + i) MyClass;
}
for (int i=9; i>=0; --i)
{
// calling the destructor directly
((MyClass*)storage + i)->~MyClass();
}
free(storage);
}
pop_back would be implemented by simply calling the destructor of the last element, and decrementing the size member variable by 1. It wouldn't, shouldn't (and couldn't, without making a bunch of unnecessary copies) free any memory.
There is no such option. Only way to resize array is allocate new array with size old_size - 1, copy content of old array and then delete old array.
If you want free object memory why not create array of pointers?
MyClass **arr = new MyClass*[size];
for(int i = 0; i < size; i++)
arr[i] = new MyClass;
// ...
delete arr[size-1];
std::vector::pop_back doesn't reallocate anything — it simply updates the internal variable determining data size, reducing it by one. The old last element is still there in memory; the vector simply doesn't let you access it through its public API. *
This, as well as growing re-allocation being non-linear, is the basis of why std::vector::capacity() is not equivalent to std::vector::size().
So, if you're really trying to re-invent std::vector for whatever reason, the answer to your question about re-allocation is don't.
* Actually for non-primitive data types it's a little more complex, since such elements are semantically destroyed even though their memory will not be freed.
Since you are using C++03, you have access to the std::vector data type. Use that and it's one call:
#include <vector>
//...
std::vector<int> ary(3);
//...
ary.erase(ary.begin() + (ary.size() - 1));
or
#include <vector>
//...
std::vector<int> ary(3);
//...
ary.pop_back();
EDIT:
Why are you trying to re-invent the wheel? Just use vector::pop_back.
Anyway, the destructor is called on contained data types ONLY if the contained data type IS NOT a pointer. If it IS a pointer you must manually call delete on the object you want to delete, set it to nullptr or NULL (because attempting to call delete on a previously deleted object is bad, calling delete on a null pointer is a non-op), then call erase.
I wonder whether memory for array member of a class be allocated in c++.
In my class, I defined array member like this:
class A
{
public:
B* B_array[1000];
}
and, in the constructor, I want to use it:
A::A()
{
for(int i = 0; i < 1000; i++)
{
B_array[i] = new B;//can i use B_array[0...999]???
}
}
B* B_array[1000];
What you have is an array of 1000 pointers to the type B.
for(int i = 0; i < 1000; i++)
{
B_array[i] = new B;//can i use B_array[0...999]???
}
Allocates memory to each pointer in the array, after this statement each pointer points to a memory on heap.
So yes you can use each of them, once this code is executed.
Yes, you can. When you enter the body of constructor, there are 1000 uninitialized pointers waiting for you to initialize them.
What you should do, though, is use std::vector<B>
class A
{
public:
std::vector<B> array;
}
A::A() : array(1000) {}
and be done with it. Vector allocates its elements dynamically.
Yes you can. Memory for 1000 pointers will be allocated always. However those pointers will not be initialised unless you do that yourself (as you are in your contructor code).
I wonder whether memory for array member of a class be allocated in c++
Yes, why not. If your doubt is about allocating an array the way you are doing, it is possible. If your doubt is about calling B's constructor while still being in A's constructor, then also there is absolutely no issues with that.
In general, however there are several things that I would take care in the code shown e.g. not hard coding the value 1000, checking for exception from new etc.. you get the idea.
And you should also be bothered about releasing the memory resource in the destructor of A explicitly.
Yes, the memory for 1000 pointers of B class instances will be allocated. You have defined an array B_array[1000] of B* objects. It's the same as int integerArray [1000]. You just store pointers in the array, not values.
However you will need to initialize them to point to the actual objects on the heap.
Why this code does not cause memory leaks?
int iterCount = 1000;
int sizeBig = 100000;
for (int i = 0; i < iterCount; i++)
{
std::auto_ptr<char> buffer(new char[sizeBig]);
}
WinXP sp2, Compiler : BCB.05.03
Because you're (un)lucky. auto_ptr calls delete, not delete []. This is undefined behavior.
Try doing something like this and see if you get as lucky:
struct Foo
{
char *bar;
Foo(void) : bar(new char[100]) { }
~Foo(void) { delete [] bar; }
}
int iterCount = 1000;
int sizeBig = 100000;
for (int i = 0; i < iterCount; i++)
{
std::auto_ptr<Foo> buffer(new Foo[sizeBig]);
}
The idea here is that your destructor for Foo will not be called.
The reason is something like this: When you say delete[] p, the implementation of delete[] is suppose to go to each element in the array, call its destructor, then free the memory pointed to by p. Similarly, delete p is suppose to call the destructor on p, then free the memory.
char's don't have a destructor, so it's just going to delete the memory pointed to by p. In my code above, it is not going to destruct each element in the array (because it's not calling delete[]), so some Foo's will leave their local bar variable un-deleted.
The auto_ptr will only live for the duration of the loop iteration and will release the object connected to it on iteration completion.
The compiler can see that in this case new[] can allocate space in the same way as new - without storing the number of elements anywhere since there's no need to call trivial char destructors - and that's why later when delete is called by the auto_ptr's destructor instead of delete[] it causes no problems since the memory block has actually been allocated in the new's way and that allocation can be paired with delete.
This is an example of a thing not to do. It's up to the compiler to decide whether to replace new[] with new. Using delete instead of delete[] and vice versa is undefined behaviour.
See Why would you write something like this? (intentionally not using delete [] on an array) for discussion of delete vs delete[].