I am working on a project as a homework for my university course of Systems Programming.
I got really confused with the matter of Pointers, Vectors, stacks and heaps.
Using C++.
I have to get a vector of objects which are courses, and those courses objects have several different fields.
What I did was this:
vector<CoursesObject> coursevector;
and then I created my Courses Object class, which contains the space left in course and name of course fields.
Now I want to add a new course, I do:
CoursesObject *theCourse = new CoursesObject(name, space);
now I want to add it to the handler vector:
coursevector.push_back(*theCourse);
With all I know, I created a vector of Courses objects on the stack, and made a new pointer to a new course that is on the heap, and added to the handler vector the pointer theCourse that points to the course object in the heap. Is what I said correct?
When I try to delete those course objects, I do:
for(int i=0; i<coursevector.size(); i++)
delete coursevector.at(i);
which gives me an error that it is not a pointer. But haven't I added to the coursevector a POINTER to the course object?
Please somebody explain, I have to handle the memory correctly and it seems that I am not getting it right.
This
vector<CoursesObject> coursevector;
is a vector of CourseObjects, so it cannot hold CourseObject pointers. When you do this:
coursevector.push_back(*theCourse);
you get a copy of the CoursesObject pointed at by theCourse stored in the vector. You do not need to delete any entries from the vector. In fact, you can't, because it doesn't hold pointers.
You program would be much simpler if you just avoided the dynamic allocation:
coursevector.push_back(CoursesObject(name, space));
You do not need to use new at all.
//This vector stores CoursesObject objects,
//not pointers to CoursesObjects.
vector<CoursesObject> coursevector;
//Construct theCourse with automatic storage
//duration.
CoursesObject theCourse(name, space);
//Copy theCourse into coursevector
coursevector.push_back(theCourse);
//theCourse will be automatically destroyed.
//coursevector (and all the objects that it contains)
//will be automatically destroyed.
all of your objects are not dynamically allocated, so you cannot delete them at any time during the program. Remember that you can only delete object once they are dynamically allocated:
int Var1 = 0; //cannot be deleted, scope and life will exist for the life of program
int * Var2 = new int; //CAN be deleted, dynamically allocated.
delete Var2; //free memory
You can however delete your last object, which is a pointer. I would grab the last element of the vector and call delete on it(which should be your pointer to the class).
when you do this:
coursevector.push_back(*theCourse);
actually you are dereferencing the pointer theCourse, so you are adding a copy of the object. You need to declare a vector of CourseObject pointers:
vector<CoursesObject *> coursevector;
Then you add an object:
coursevector.push_back(theCourse);
Now your code to delete the objects should work:
for(int i=0; i<coursevector.size(); i++)
delete coursevector.at(i);
coursevector can hold only CoursesObjects and not pointers to CoursesObjects, so you needn't use the new operator (check #Mankarse's answer). But, if you still want to hold pointers, then change the definition of coursevector to
vector<CoursesObject*> coursevector;
and push_back the value of the pointer as it is:
coursevector.push_back(theCourse);
Related
If I use this line
std:vector<MyObject>* vec = new std::vector<MyObject>(100);
If I create MyObject's in the stack and add them to the vector, they remain in the stack, right ?
MyObject obj1;
vec->push_back(obj1);
So if it go to the stack, than MyObject's added to the vector will be gone after method ends ? What will I have inside the vector than? Garbage?
Should I use this instead ?:
std:vector<MyObject*>* vec = new std::vector<MyObject*>(100);
And if so, what about objects and primitives inside each MyObject ?
Should they also be dynamically created ?
Thank You
The std:vector as any other Standard Library container copies elements into itself, so it owns them. Thus, if you have a dynamically allocated std::vector the elements that you .push_back() will be copied into the memory managed by the std::vector, thus they will be copied onto the heap.
As a side note, in some cases std::vector may move elements if it is safe to do so, but the effect is the same - in the end, all the elements are under std::vector's jurisdiction.
A std::vector<MyObject> looks something like this (in reality it's much more complex):
struct Vector {
MyObject* data;
int size;
}
As you can see, the data is not directly inside the vector object. The vector always allocates the memory for the data on the heap. Here's what happens when:
you call .push_back: The vector copies the object into its own data block (which is on the heap and owned by the vector)
you copy the vector: The copied vector allocates new memory and copies all data from the existing vector into it
As you can see, the vector owns his data. That means, if you push_back a object into it, it doesn't matter where it came from because it gets copied.
If you have a std::vector<MyObject>* you have a pointer to a vector. This vector also owns his data, but you only have a pointer to it. That means, you have to delete it exactly once, otherwise you'll get a memory leak or a crash. Passing around pointers to a vector is OK, but need one class or function that "owns" it. This class/function has to guarantee that the vector still exists when the pointer to it is used.
The third case is a std::vector<MyObject*>. As every vector, this one also owns his data. But this time, the data is only a pointer. So the vector only owns the pointer, but not the objects to which the pointers are pointing. If you do something like this:
std::vector<MyObject*> getObjects() {
MyObject obj1("foo");
MyObject obj2("bar");
std::vector<MyObject*> vec;
vec.push_back(&obj1);
vec.push_back(&obj2);
return vec;
}
The returned vector only contains garbage because you only saved the address to a object on the stack to it. These objects are destroyed when the function returns, but the pointers in the vector are still pointing to that memory block on the stack.
Additionally, keep in mind that this
std:vector<MyObject*>* vec = new std::vector<MyObject*>(100);
Doesn't store heap allocated objects to the vector. It just stores pointers of type MyObject. If you want to do something like that remember to create the objects first, before you use them. You can do that with something like the following:
for (int i = 0; i < vec->size(); i++) {
vec->at(i) = new MyObject();
}
I have a vector like std::vector<AnyObject*> myVector; and I would like to delete an element in my vector without changing position of my other elements. How can I do this ? I have two solutions, tell me if they are good:
AnyObject* initial;
std::vector<AnyObject*> myVector(10, initial);
AnyObject* object = myVector.at(4);
delete object;
or
AnyObject* initial;
std::vector<AnyObject*> myVector(10, initial);
delete myVector.at(4);
What happens in the first solution when I delete object ? Am I also deleting the pointer in the vector or just the object ?
EDIT :
When I wrote AnyObject* initial;, I know initial isn't initialized, I wanted just say what happens if I a have a vector of initialized pointers and if I wanted delete one pointer without changing position of the other pointers.
EDIT2:
For the context of the problem, I have a class PointCloud and another class SubsampledPointCloud. I want subsampled my all clouds with the same size of the smallest cloud, so among my subsampled point cloud, I have at least one cloud that have the same size of its point cloud. So to build my vector of SubsampledPointCloud, I have a vector of PointCloud initialized, a variable minPointCloudSize equals to the minimum size among my point clouds and I do this :
std::vector<SubsampledPointCloud*> subcloud(clouds.size());
for (std::size_t i = 0; i < clouds.size(); i++) {
if (clouds.at(i).size() > minPointCloudSize)
subcloud.at(i) = subPointCloud(clouds.at(i)); //subPointCloud is a function
//that return a SubsampledPointCloud*
else
subcloud.at(i) = clouds.at(i);
}
and later, I don't need of this subsampled point cloud, so I'm deleting all of this except if the sub cloud with the same size of the original cloud.
Of course, SubsampledPointCloud inherited of PointCloud.
I have two solutions, tell me if they are good
Both of your solutions have UB - you read from uninitialized variable initial. If you manage to put correctly initialized pointers to your vector, then both variants would have the same effect - if fifth pointer in the vector not equal to nullptr, object it points to would be destroyed and memory released. You should understand that delete does not modify argument passed to it, so calling delete would not alter pointer itself and unless it is not equal to nullptr you would have dangling pointer left in the vector. It would be your job to reassign new value to it or to avoid using it after that. Or remove it from the vector calling vector methods.
Am I also deleting the pointer in the vector or just the object ?
You are only deleting object, pointer would have exactly the same value ie point into memory where object used to be.
A segmenation fault in both cases, as you haven't actually created any AnyObjects, only the vector of null pointers.
In general, if you have a vector of pointers to objects, you can delete the object by deleteing the object as you have done, and then setting the pointer to null, to denote that it doesn't point to an object.
To use your example, glossing over the fact you haven't created any objects:
AnyObject* initial;
std::vector<AnyObject*> myVector(10, initial);
delete myVector[4];
myVector[4] = 0;
std::vector<AnyObject*> myVector(10, initial);
This statement will initialize vector with 10 initial object. initial is memory reference and when you delete it that deallocates memory that was allocated for initial object and will make all vector element pointing to invalid memory location in both case. If you will try to access it after delete in both case, the behavior will be undefined.
Your premise is flawed. You shouldn't use raw pointers to handle object lifetimes, use std::unique_ptr (or std::shared_ptr if the lifetime really is shared)
Then your example would look like
std::vector<std::unique_ptr<AnyObject> > myVector(10, nullptr);
// other code
myVector[index] = make_unique<AnyObject>(args...);
// other code
myvector[other_index].reset(nullptr);
I have had a good look at some other questions on this topic and none of them (to my knowledge) address how to correctly erase items from a stl list of objects which contain dynamicically assigned memory vs. a stl list of objects that don't contain dynamically assigned memory.
I want to use a list of objects. Take this object for example (which contains no dynamically assigned memory):
class MyPoint {
public:
MyPoint(int _x,int _y)
{
x = _x;
y = _y;
}
private:
int x;
int y;
};
So I might create a list of objects (not pointers to them), add things to it and then erase an element:
list<MyPoint> myList;
myList.push_back(MyPoint(3,4));
myList.push_back(MyPoint(1,2));
myList.push_back(MyPoint(8,8));
myList.push_back(MyPoint(-1,2));
list<MyPoint>::iterator it;
it = myList.begin();
advance(it,2);
myList.erase(it);
My list now contains:
(3, 4)
(1, 2)
(-1, 2)
QUESTION 1a: do I need to do anything else to the erased object or will the memory be taken care of?
QUESTION 1b: if the program ends, do I need to do something with the remaining objects in the list? Do I need to delete them all and deal with their memory somehow?
Ok, now consider an alternative version of the class that allowed a point in N-dimensional space. I.e., I could dynamically assign an array of length N to hold the N points inside the class (I have spared you the implementation as that is not in question here). The destructor of the class would then delete the dynamically assigned array using 'delete'.
class MyDynamicPoint {
public:
MyDynamicPoint(int N)
{
points = new int[N];
}
~MyDynamicPoint()
{
delete points;
points = NULL;
}
private:
int *points;
};
I might now create a list of pointers to the objects, instead of the objects themselves:
list<MyDynamicPoint*> myList;
myList.push_back(new MyDynamicPoint(8));
myList.push_back(new MyDynamicPoint(10));
myList.push_back(new MyDynamicPoint(2));
myList.push_back(new MyDynamicPoint(50));
list<MyDynamicPoint*>::iterator it;
it = myList.begin();
advance(it,2);
myList.erase(it);
QUESTION 2a - Is the above correct? I.e. Because this new version of the class would contain some dynamically assigned memory, does this mean I have to create a list of pointers to objects, not the objects themselves?
QUESTION 2b - Given that I have just erased the pointer from the list, where do I call delete to deal with the fact there is now dynamic memory to be deleted in the objects? Or does the erase method of stl list call the destructor of the object, taking care of it?
Many thanks in advance for any help,
Best,
Adam
When you have a class with data members that have automatic storage duration (i.e. their lifetime is tied to the instance of this class) like this:
class MyPoint {
private:
int x;
int y;
};
and you will use list<MyPoint> myList;, then this instance of std::list is also an object with automatic storage duration, that will be cleaned up automatically and by the time the container is destructed, so are the elements it holds. Everything is taken care of.
But the latter version is not very lucky choice... not only that you have a container holding pointers, you even decided to create a data member of class Point that will be allocated dynamically. At first note that everything that has been allocated by calling new should be freed by calling delete and everything allocating by calling new[] should be freed by calling delete[].
In this situation, you are allocating the memory when the object is constructed and cleaning it up when the object is destructed:
MyDynamicPoint(int N)
{
points = new int[N];
}
~MyDynamicPoint()
{
delete[] points;
points = NULL;
}
private:
int *points;
You would achieve the same by using some std::vector or std::array instead of the C-style array and you wouldn't have to take care of the memory management on your own:
MyDynamicPoint(int N) : points(std::vector<int>(N, 0)) { }
private:
std::vector<int> points;
the std::vector object will take care of memory management for you.
And last thing: when you dynamically allocate an element and store it into the container:
myList.push_back(new MyDynamicPoint(8));
you need to free this memory on your own, erasing the pointer from the list is not enough:
list<MyDynamicPoint*>::iterator it;
...
delete *it;
myList.erase(it);
So whatever you want to achieve, always prefer objects with automatic storage duration if the situation allows it. There's nothing worse than being forced to taking care of memory management manually and dealing with unpleasant problems such as memory leaks later.
QUESTION 1a: do I need to do anything else to the erased object or will the memory be taken care of?
You don't need to do anything.
QUESTION 1b: if the program ends, do I need to do something with the remaining objects in the list? Do I need to delete them all and deal with their memory somehow?
You don't need to do anything.
QUESTION 2a - Is the above correct?
The code is not correct. You're violating The Rule of Three. In particular, the automatically-generated MyDynamicPoint's copy constructor and assignment operator will make a bitwise copy of the points pointer. If you copy an instance of MyDynamicPoint, you'll end up with two object sharing the same points pointer:
When one of the objects goes of scope, the other becomes unusable.
When the second object goes out of scope, its destructor will attempt to free memory that's already been freed. This is undefined behaviour.
I.e. Because this new version of the class would contain some dynamically assigned memory, does this mean I have to create a list of pointers to objects, not the objects themselves?
No, it does not mean that. In fact, you should probably continue to store objects by value. However, you do need to fix the rule of three.
QUESTION 2b - Given that I have just erased the pointer from the list, where do I call delete to deal with the fact there is now dynamic memory to be deleted in the objects? Or does the erase method of stl list call the destructor of the object, taking care of it?
Since you have a list of raw pointers, the destructors will not be called automatically. The easiest way to fix that is to either store objects by value, or use std::unique_ptr or std::shared_ptr instead of raw pointers.
To question 1, there is nothing you need to do. As you store the objects by value the compiler and the library will handle everything.
However, when you store pointer as in the second case, you need to delete those pointers that you have allocated with new, or you will have a memory leak.
And you have to delete the pointers before doing the erasing, as that can invalidate the iterator:
delete *it;
myList.erase(it);
I think following should work
MyPoint* ptr = myList.back();
delete ptr;
myList.pop_back();
OR
MyPoint* ptr = myList.back();
delete ptr;
myList.erase(ptr);
Besides a lot of member functions, my Graph class has 3 main members: a vector of pointers to its vertices, called "vertex", a vector of pointers to its edges, called "edge", and an integer counter variable. I started/attempted to write the destructor to deallocate the memory from the vectors, but I'm not sure if I am doing it correctly. And what do I do about the counter? I tried to say "delete counter," but it's not a pointer (oops).
Graph<Object,Weight>::~Graph(){
for(unsigned int i=0; i<vertex.size(); ++i){
delete vertex[i]; }
for(unsigned int j=0; j<edge.size(); ++j){
delete edge[j]; }
//counter?
}
Deleting depends on the way you allocated, see The difference between delete and delete [] in C++
As for your int member, since you didn't dynamically allocate it (you didn't use new) you don't have to delete it.
Assuming the type of vertex is std::vector<Vertex*> and you create the vector as follows:
vertex.push_back( new Vertex );
your clean up code looks correct.
But, I urge you not to do this. Declare vertex as std::vector<std::unique_ptr<Vertex>> and you don't need to worry about deleteing the individual vector members anymore.
If you're using Boost, you could also make vertex a boost::ptr_vector.
As for the counter variable, unless you're newing the counter somewhere during class construction, you don't need to delete it.
is counter a plain ordinary int variable? If so, you're not in charge of its lifetime.
The delete keyword is only to be used when you've created an object with the new keyword. (And even then, only when there isn't something else in your program, such as shared_ptr which is doing the delete for you)
When using new/delete you're taking over from the language and managing the lifetime/existance of an object yourself. ordinary variables are created and destroyed automatically, meaning you don't need to worry about them.
You can delete an array of pointers with:
del[] arr; // arr is array of pointers.
Whereas, if counter is from stack, the program will take care of it, and you as programmer don't need to worry about freeing that memory.
I'm assuming that vertex and edge are allocated using new? then what you have written is fine but if you declared your vertex and edge as an array and newed using new [] operator then you need to use the delete [] call instead of delete, if the counter was not declared as a pointer and newed then there is no need to delete the counter.
As a design decision you should consider declaring your vertex and edge objects as boost::shared_ptr or unique_ptr so that they are reference counted and when the Graph object goes out of scope they are automatically cleaned up so you don't even need to flesh out your destructor.
If you have c++11 then you can use the std versions and not need boost like std::shared_ptr and std::unique_ptr.
So I have a pointer to an array of pointers. If I delete it like this:
delete [] PointerToPointers;
Will that delete all the pointed to pointers as well? If not, do I have to loop over all of the pointers and delete them as well, or is there an easier way to do it? My google-fu doesn't seem to give me any good answers to this question.
(And yeah, I know I need to use a vector. This is one of those "catch up on C++" type assignments in school.)
Yes you have to loop over the pointers, deleting individually.
Reason: What if other code had pointers to the objects in your array? The C++ compiler doesn't know if that's true or not, so you have to be explicit.
For an "easier way," two suggestions: (1) Make a subroutine for this purpose so at least you won't have to write the code more than once. (2) Use the "smart pointer" design paradigm where you hold an array of objects with reference-counters, then the objects are deleted when the objects are no longer referenced by any code.
I agree with Jason Cohen though we can be a bit clearer on the reason for needing to delete your pointers with the loop. For every "new" or dynamic memory allocation there needs to be a "delete" a memory de-allocation. Some times the "delete" can be hidden, as with smartpointers but it is still there.
int main()
{
int *pI = new int;
int *pArr = new int[10];
so far in the code we have allocated two chunks of dynamic memory. The first is just a general int the second is an array of ints.
delete pI;
delete [] pArr;
these delete statements clear the memory that was allocated by the "new"s
int ppArr = new int *[10];
for( int indx = 0; indx < 10; ++indx )
{
ppArr[indx] = new int;
}
This bit of code is doing both of the previous allocations. First we are creating space for our int in a dynamic array. We then need to loop through and allocate an int for each spot in the array.
for( int indx = 0; indx < 10; ++indx )
{
delete ppArr[indx];
}
delete [] ppArr;
Note the order that I allocated this memory and then that I de-allocated it in the reverse order. This is because if we were to do the delete [] ppArr; first we would lose the array that tells us what our other pointers are. That chunk or memory would be given back to the system and so can no longer be reliably read.
int a=0;
int b=1;
int c=2;
ppArr = new int *[3];
ppArr[0] = &a;
ppArr[1] = &b;
ppArr[2] = &c;
This I think should be mentioned as well. Just because you are working with pointers does not mean that the memory those pointers point to was dynamically allocated. That is to say just because you have a pointer doesn't mean it necessarily needs to be delete. The array I created here is dynamically allocated but the pointers point to local instances of ints When we delete this we only need to delete the array.
delete [] ppArr;
return 0;
}
In the end dynamically allocated memory can be tricky and anyway you can wrap it up safely like in a smart pointer or by using stl containers rather then your own can make your life much more pleasant.
See boost pointer container for a container that does the automatic deletion of contained pointers for you, while maintaining a syntax very close to ordinary STL containers.
Pointers are pretty much just memory references and not spiffy little self-cleaning .net objects. Creating proper destructors for each class will make the deletion a little cleaner than massive loops throughout the code.
Let's take a (pseudocoded) real world example .Imagine that you had a class like this:
class Street
{
public:
Street();
~Street();
private:
int HouseNumbers_[];
}
typedef *Street StreetSign;
If you have an array of street signs, and you delete your array of streetsigns, that doesn't mean that you automatically delete the sreets. They re still there, bricks and mortar, they just don't have those signs pointing to them any more. You have got rid of those specific instances of pointers to the streets.
An array of pointers is (conceptually) a bit like an array of integers, it's an array of numbers representing the memory locations of various objects. It isn't the objects themselves.
If you delete[] the array of pointers, all you have done is delete an array of integers.
I think you're going to have to loop over I'm afraid.
I don't know why this was answered so confusingly long.
If you delete the array of pointers, you will free
the memory used for an array of usually ints.
a pointer to an object is an integer containing the adress.
You deleted a bunch of adresses, but no objects.
delete does not care about the content of a memory space,
it calls a destructor(s) and marks the mem as free.
It does not care that it just deleted a bunch of adresses
of objects, it merely sees ints.
That's why you have to cycle through the array first! and call delete
on every element, then you can delete the storage of the array itself.
Well, now my answer got somewhat long... .... strange... ;)
Edit:
Jason's answer is not wrong, it just fails to hit the spot. Neither
the compiler nor anything else in c(++) cares about you deleting stuff that is elsewhere
pointed to. You can just do it. Other program parts trying to use the deleted objects
will segfault on you. But no one will hinder you.
Neither will it be a problem to destroy an array of pointers to objects, when the objects
are referenced elsewhere.