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.
Related
If I have class and vector of pointers in class how should I write destructor to properly free memory?
Is it correct?
~Class()
{
for(int i = 0; i<v.size(); i++)
{
delete v[i];
}
}
Or should I also erase elements from vector? Or any other solutions?
~Class()
{
for(int i = 0; i<v.size(); i++)
{
delete v[i];
v.erase(e.begin() + i);
}
}
If I have class and vector of pointers in class how should I write destructor to properly free memory? Is it correct?
It depends.
Do the pointers point to objects that were allocated with new and is this class the owner of those dynamic objects (i.e. is this class responsible for their destruction)? If not, then it's not correct.
Or should I also erase elements from vector?
Your example for erasing elements of the vector is wrong. It will skip half of the elements and thus will not call delete all pointers. After first iteration, first element will have been erased, so the next element has been shifted to the index 0, but next loop deletes and erases the element in index 1.
There's no point in erasing elements of the vector, because it is immediately about to be destroyed.
Or any other solutions?
If you intend for the class to own dynamically allocated objects, prefer using a vector of objects instead of pointers. If you need a vector of pointers for example to allow run time polymorphism, then use a vector of std::unique_ptr. That way you don't need to implement a destructor as the automatically generated would be just fine.
If your class is to supposed to own the objects pointed to, then its sufficient to do:
for (auto p : v) delete p;
If the vector itself is the member of the class then its elements are getting deleted when the class instance object is destroyed, you dont need to do this manually.
And in your example you are also doing it wrong. If its a std::vector you could just call vector's clear() method. Otherwise you would call delete[] p; where p is the pointer to the vector elements itself.
C++ Memory Leak using list class and push_back
void EMAdd(int n)
{
list<Employee*> em;
for (int i = 1; i <= n; i++)
em.push_back(new Employee());
}
Q1. at the end , the destructor of class list automatically deletes the nodes of em?
Q2. But why this function still has a memory leak?
Thanks,
I would appreciate your answer!
The destructor of Employee is not called. You have a list of pointers to Employee objects, not a list of Employee objects. When the list's destructor is called it will destroy the pointers to the Employee object, but not the objects they point to which you created with new Employee(). They will still be in memory but the only references to them are lost when the list is destroyed, leaking that memory.
Remember every call to new must have a matching call to delete somewhere. However, better yet don't use pointers at all and simply use a list of Employee objects directly.
void EMAdd(int n)
{
list<Employee> em;
for (int i = 1; i <= n; i++)
em.push_back(Employee());
}
Since each element in std::list is already dynamically allocated, a list of pointers is redundant and essentially gives you a set of pointers to pointers.
You should have a list of unique_ptrs so that the memory will be freed upon destruction:
std::list<std::unique_ptr<Employee>> em;
But as David Brown said, you shouldn't be using pointers to begin with.
Suppose I have an array of objects of type Foo in C++:
Foo array[10];
In Java, I can set an object in this array to null simply by:
array[0] = null //the first one
How can I do this in C++?
Use pointers instead:
Foo *array[10];
// Dynamically allocate the memory for the element in `array[0]`
array[0] = new Foo();
array[1] = new Foo();
...
// Make sure you free the memory before setting
// the array element to point to null
delete array[1];
delete array[0];
// Set the pointer in `array[0]` to point to nullptr
array[1] = nullptr;
array[0] = nullptr;
// Note the above frees the memory allocated for the first element then
// sets its pointer to nullptr. You'll have to do this for the rest of the array
// if you want to set the entire array to nullptr.
Note that you need to consider memory management in C++ because unlike Java, it does not have a Garbage Collector that will automatically clean up memory for you when you set a reference to nullptr. Also, nullptr is the modern and proper C++ way to do it, as rather than always is a pointer type rather than just zero.
So, forget Java here, it's not helping you. Ask yourself; what does it mean for an object to be null? Can an object be null? The answer is no, an object can not be null, but a reference (pointer in C++ terms) to one can be.
In java you have reference types, which are similar to pointers under the hood. However, you cannot set objects to null even in java, only references.
In C++ you have fully fledged objects and pointers and references to objects. A pointer to an object (or primitive type) can be null, but an object itself cannot.
So, when you create an array of Foo objects you have, well, an array of Foo objects. You don't have pointers, you have objects. If your array were an array of pointers to objects then yes, you could initialize them to null (nullptr in C++0x), i.e., they don't refer to a valid object.
Other way that you have is using one dynamic array of pointers of Foo like this:
Foo** array = new Foo*[10];// Pointer of array of pointers.
Then you can initialize all this pointers to objects Foo
for(int i=0;i<10;i++)
array[i] = new Foo();// Give memory to pointers of object Foo in array
assign null to one item of array:
array[0] = 0;
I think that in C++, NULL is 0. This means it can even be assigned to an int or anywhere a 0 is acceptable. Conventionally, it's only used with pointers.
For delete this memory:
for(int i=0;i<10;i++)
delete array[i];
and finally
delete[] array;
Code Example:
#include <iostream.h>
#include <stdio.h>
class Foo
{
private:
int a;
public:
Foo()
{
a = 0;
}
void Set_V(int p){a = p;}
int Get_V(){return a;}
};
int main()
{
Foo **array = new Foo*[10];
for(int i=0;i<10;i++)
{
array[i] = new Foo();
}
//array[0] = 0;
for(int i=0;i<10;i++)
array[i]->Set_V(i);
for(int i=0;i<10;i++)
cout<<array[i]->Get_V()<<endl;
for(int i=0;i<10;i++)
delete array[i];
delete[] array;
return 0;
}
so is there away to "remove" an element in the array without creating a new one? i.e making a hole in the array of some sort?
In C++, if you have an array:
Foo array[10];
Then all 10 elements will be default-constructed. In general, there's no concept of array elements being in use vs. "removed". One way to track this idea is to make having actual values in the array elements optional, as in:
boost::optional<Foo> array[10];
You can read about the boost library's optional<> library at http://www.boost.org/doc/libs/release/libs/optional/
For the sake of documenting alternatives, I'll cover a hideous one. You could call the destructor on one of the elements: array[3].~Foo(); This is very dangerous as when the array itself goes out of scope, the destructor for each element will be called, and a precondition for that is to have a properly constructed object, so you have to be sure to have constructed a Foo in that element again beforehand (using "placement" new). There is nothing in the array itself that will help you keep track of which elements have had their destructors called by you - you'd need to track that yourself (having some record of this inside the objects would probably work in practice, but accessing the object after destruction is undefined behaviour). You'd need to be very careful that in all code paths - including those due to exceptions - you tracked the momentarily unused array elements. You really don't want to do this.
If your concern is to remove an element from the array to save memory, then use smart pointers:
shared_ptr<Foo> array[10];
You can then control specific array elements independently, with only still-populated elements being destructed when the element goes out of scope. Suitable smart pointers are available in boost or C++11, or you could use std::auto_ptr<> but should carefully read about its semantics beforehand to see if it's suitable and how to safely use it.
Separately, if there's a Foo::operator=(Some_Type*) then you could set array[3] = NULL;, and it would do whatever that assignment operator did to array[3]. Still, if Foo is not a pointer, it is probably a bad idea for it to allow someone to assign NULL to it.
I am storing dynamically allocated class pointers in a vector like below.
vector<Test *> v;
Test *t1 = new Test;
Test *t2 = new Test;
v.push_back(t1);
v.push_back(t2);
Now, if i have to free Test objects, i have to loop through entire vector and free one by one and then do a clear.
for(int i = 0; i<v.size(); i++)
{
delete v[i];
}
v.clear();
Is there any function in vector to free all internal objects. That function should call Test class destructor for each object.
I understand that it is difficult for Vector class whether the pointer is address of a local object or dynamically allocated.
But still, whenever developer is confident that all are dynamically allocated he could have used freeing function if provided.
Although vector is treated as advanced Array, freeing objects in an array is much easier like below.
Test *a = new Test[2];
delete []a;
Is there any function in vector to free all internal objects ?
Your examples don't do the same thing at all.
If you want the vector equivalent of this array code:
Test *a = new Test[2];
delete []a;
it is simply
std::vector<Test> a(2);
If you have a vector of pointers to dynamically allocated objects, you need to delete every one of them, as in your example:
for(int i = 0; i<v.size(); i++)
{
delete v[i];
}
but the same thing is true for an array:
Test *t1 = new Test;
Test *t2 = new Test;
Test **a = new Test*[2];
a[0] = t1;
a[1] = t2;
also has to be deleted with such a loop:
for(int i = 0; i<2; i++)
{
delete a[i];
}
delete[] a;
In the first case, you have two objects stored in a container of some sort. That container may be a vector, or it may be an array.
In both cases, because the objects are stored directly in the container, their destructors are called when the container is destroyed. You don't need to do anything to destroy or delete individual members, you just have to destroy the container (which is simpler with the stack-allocated vector, where you don't even need to call delete[])
But if your container stores pointers to dynamically allocated objects, then it is your responsibility to delete those objects at some point. And that is true whether your container is an array or a vector.
No, there is no way to request that a std::vector full of pointers automatically call delete on all of its elements.
There are, however, other, third-party containers that will make this sort of thing easier by automatically deleting pointers when they are removed from the vector, or when the vector destructs. For example, boost::ptr_vector and friends.
The short answer is no. C++ does not provide a vector of pointers free'ing function.
The long answer is twofold:
Use smart pointers, and forget about free'ing (there's shared_ptr or unique_ptr in c++0x that will serve most of your needs). Alternatively, use a Boost ptr_vector like Tyler suggested.
It's not that hard to write a simple generic algorithm to delete each item in a container (use a template with iterators).
(warning: untested code, have no time to check it)
template<class It>
void delete_clear_ptr_cont( const It &beginIt, const It &endIt )
{
for( auto it = beginIt; it != endIt; ++it )
{
delete it;
}
erase( beginIt, endIt );
}
No, vector isn't aware that it may be instantiated with pointers. And even if it was, there are situations where you don't own the pointers and you don't want the delete behavior.
In most cases we simply use a vector of smart pointers, like shared_ptr. However, there are times where shared_ptr isn't appropriate. For those cases we have a functor in our toolbox like this:
#include <functional>
template<typename T>
struct PointerDelete : public std::unary_function<T*, T*>
{
T* operator()(T*& p) const
{
delete p;
return 0;
}
};
Then, assuming you have a vector<Foo*>, you could do either:
#include <algorithm>
std::for_each(v.begin(), v.end(), PointerDelete<Foo>());
// or
std::transform(v.begin(), v.end(), v.begin(), PointerDelete<Foo>());
If you can use the boost library, there are also ptr_containers, which are containers that take ownership of pointers and do the delete for you automatically on container destruction.
I asked the same question before and I was suggested to use Boost library and you will find great tips
here or simply you can understand smart pointers as follows :
Instead of having a vector of pointers you will have a vector of smart pointers , as for each new you will make it will delete itself without you having to worry .
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.