Using std::List with object pointers - c++

I am writing a quad tree which stores pointers to collidable objects in an stl list.
I want the quad tree to be able to move the objects from node to node depending on their position in the world, and would like to just get something confirmed:
If I remove the pointer from the list, to insert the object into another tree node (such as the parent tree node), will the destructor for the pointed-to object be called? For clarification, I do not want the object destroyed, as it is used & managed elsewhere in the program.
Thanks, in advance.

The actual object in the list (i.e. the pointer) will be destructed, but not what the pointer points to.
It might be a little confusing to begin with, but if you see the pointer, and what it points to, as completely separate entities it makes a lot more sense.

The destruction of an object is determined by its storage duration. If an object has automatic storage duration (like a local variable), it will be destroyed when it goes out of scope. If an object is dynamically allocated (using new), it will only be destroyed when you do delete on it. If it has static storage duration, it will be destroyed when the program ends.
If you are just copying the pointer out of one node and into another and as long as the object it points at hasn't been destroyed according to the above rules, the pointer will continue to point at the same valid object.

no, destructors are never called on pointers in STL. It only gets destroyed when you call delete explicitly on the object pointed to (or if the object when stored on the stack goes out of scope) or if you use smart pointers.

I'm not sure if what you say will happen, but anyway it might be a good practise to reset your pointer to NULL before deleting the instance. Also, remember to make the pointed-object to be pointed by the correct node, that probably will be the node that was pointing to the node you erased.

Related

Does unique_ptr automatically destruct when not referenced?

Similar to the concept of GC in Java, when an object is not referenced anymore by something else, it gets marked for GC.
Does unique_ptr work similar to this?
If say I have a data structure (a tree) with nodes containing left/right std::unique_ptr<BSTNode>. Say I have a remove function remove(std::unique_ptr<BSTNode>& root, int val), if I go to the parent of the BSTNode containing val, and assign nullptr to the left or right child field (which is the std::unique_ptr<BSTNode> containing val), would the smart pointer self destruct?
Or should I reset the smart pointer inside of the remove function as well? This question is mostly a scope issue that I am not understanding.
if I go to the parent of the BSTNode containing val, and assign nullptr to the left or right child field (which is the std::unique_ptr containing val), would the smart pointer self destruct?
The smart pointer will destroy the thing it points to.
It will not destroy itself (which is what self-destruct means; you may have confused terminology here).
The key to unique_ptr is understanding the lifespan of stack variables.
There's nothing inherent in unique_ptr that's different from other stack variables, just the use of its destructor to clean up the owned content. This is an idiom widely used before these pointers, referred to as RAII Resource Acquisition Is Initialisation.
If you have a unique_ptr on the stack, ie: declared inside some scope, it executes its destructor when you exit that scope and the stack variables are deleted.
If you have it inside some struct or class allocated on the heap, it executes its destructor when that container is deleted.

Deleting objects in an stl list using the erase function in c++

So I'm trying to implement some memory management techniques here. In my program, I created an stl list so that it would contain objects of the class "Blast" with it's respective iterator:
list<Blast> blasts;
list<Blast>::iterator it1;
I've looked around and found that if you use the erase function, it will call the destructor of the class, and then delete the iterator to which it points to the object and return some other pointer (iterator). However, if the class is a POD, then the call for the destructor won't do anything, hence all the information that was saved in that object will be kept in memory.
To go around this, I tried to allocate the object dynamically so that I could use the delete function to wipe it out of memory as such:
Blast *blast;
blast = new Blast;
However, here I encountered a problem. When i tried to push the object onto the list, it only lets me push the pointer:
blasts.push_back(*blast);
At first, I didn't think anything about it. So I continued:
if(it2->getX() > 600) {
delete &it2;
it2 = blasts.erase(it2);
}
I realized then, that what this does is that it erases the pointer that was pointing to the object, and then the pointer that was pointing to the pointer pointing to the object.
I'm not entirely sure if that is actually correct, as I have no way of knowing if there's a memory leak. So my question is this:
What do I have to do to erase the object from memory BEFORE deleting whatever pointer is pointing to that object? Is my implementation correct? Is it's result the same as if I were to just simply push the object onto the list?
then delete the iterator to which it points to the object and return some other pointer (iterator)
Not a pointer, an iterator.
hence all the information that was saved in that object will be kept in memory.
No, that's not true.
When i tried to push the object onto the list, it only lets me push the pointer:
Huh? If you have a std::list<Blast> then of course you can't store a Blast* in the list, that's not the same type. Maybe you want to change the list to a std::list<Blast*>?
delete &it2;
This is wrong, it tries to delete the iterator, not the list element it refers to. To delete the element it points to you want:
delete &*it2;
But if you still have a std::list<Blast> then that will try to delete an object owned by the list, which would be very wrong and cause bugs.
I think you should just stick to std::list<Blast> and forget this entire question - it seems to be based on a misunderstanding that erasing an element doesn't destroy the object, which is not true. If your problem is that Blast objects have pointer members that point to dynamically allocated memory then add a destructor to Blast to make it clean up properly.

Pointer Ownership

I have an array of pointers: pArray[rows][columns], where each element can contain a pointer to an object. Some of the objects were instantiated in main() on the heap, and some were instantiated by objects themselves also on the heap: That is, I passed pArray to an object member function, and that function created a new object, and put a pointer to it in pArray.
Now when I want to delete pointers to objects from pArray, is there ownership in play here? Meaning, if an object created a new object and placed a pointer to it in pArray, can only the creator object call delete on that pointer? Or can I do it from main(), and other objects by passing the array to them?
Some more details:
The code simulates a predator prey model on a grid (pArray). So I begin by reading in the initial grid config from a file, and instantiate objects (predators, and prey), on pArray from main(). But predators and prey can breed, so objects spawn new objects and by passing pArray to them, they instantiate their children on pArray.
With raw pointers ownership is purely a concept. As long as you are working with raw pointers, it is entirely up to you to assign ownership of pointed object to anyone and anything. It is a matter of your design. There's no such "rule" that the object should be deleted by whoever created them. Ownership can be retained or passed on. Ownership can be shared (as in reference-counted ownership schemes). Again, it is a matter of your design and your intent.
Various smart pointer classes will help you to express your intent and implement your intent. With raw pointers you have to remember who owns what and do everything manually.
No, there is no "ownership" on pointers in C++, if the pointer is valid (contains proper reference to data / object), you can deallocate it anywhere issuing delete command.
The destructor of objects is subject to the same public/protected/private like every other method. So, if the destructor is public, anyone can call delete on the object.
The only important thing is that it happens exactly once, and only after nobody is using the object anymore.
There is no ownership concept for pointers in C++ .As far as I understood your question, Yes you can delete that object from main() in case of dynamic memory allocation. The memory allocated to that object would only be freed only when the program ends or the Object array goes out of scope and the destructor for the class is called.

Invalid access error when trying to access a pointer to an object in a vector

I've a method in a class that get's a pointer to another object (of a different class)and adds an object (of another different class) to a vector that is a member variable of the first object (the one that is passed as a parameter). This is the code:
ObstacleManager::ObstacleManager(Application *lApp)
{
app=lApp;
GLfloat obstacleVerts[12]={
-0.1f,-0.2f,0.0f,
0.1f,-0.2f,0.0f,
-0.1f,0.2f,0.0f,
0.1f,0.2f,0.0f
};
StandardObstacle obstacle(obstacleVerts,-0.7f,0.0f,4);
obstacle.manager=this;
lApp->characters.push_back(&obstacle);
}
I think the problem is that the obstacle object gets released when it shouldn't, because if I change the code and create the obstacle with a "new" (if you create an object with new you have to manually delete it, don't you?) It works. Like this:
ObstacleManager::ObstacleManager(Application *lApp)
{
app=lApp;
GLfloat obstacleVerts[12]={
-0.1f,-0.2f,0.0f,
0.1f,-0.2f,0.0f,
-0.1f,0.2f,0.0f,
0.1f,0.2f,0.0f
};
StandardObstacle *obstacle=new StandardObstacle(obstacleVerts,-0.7f,0.0f,4);
obstacle->manager=this;
lApp->characters.push_back(obstacle);
}
Is there a way to prevent this from happening?
You are passing the address of a local object to the vector, the local object does not exist once the constructor returns and your vector then has a pointer which points to invalidated memory.
You will have to make the object persist, possible ways are:
Just push the object by value or
Use dynamically allocated object but instead of raw pointer use a smart pointer like shared_ptr as the vector element type.
Yes, you either create the object with new or use smart pointers instead.
Your intuition is correct:
ObstacleManager::ObstacleManager(Application *lApp)
{
//...
StandardObstacle obstacle(obstacleVerts,-0.7f,0.0f,4);
obstacle.manager=this;
lApp->characters.push_back(&obstacle);
} //obstacle is destroyed here
The object obstacle is created in automatic storage. Its lifetime is limited by its enclosing scope, which is the closing bracket in the constructor.
So you take the address of an object, push it into your vector, and then the object is destroyed. That means that, inside the vector, you now have a dangling pointer.
This will most certainly lead to undefined behavior.
You can either use new, as you have, and make sure to clean up the memory. Or you can use smart pointers - which is more C++-ish than raw pointers.

Question about pointers and objects?

Just wondering, if I statically create an object that has a pointer as a data member and then the object goes out of scope, what happens to the pointer?
Chuma
Nothing happens to the pointer at all, it just ceases to exist. If it was pointing to something that needed to be freed, you just got a memory leak.
Either add code to the destructor that does the proper cleanup of the pointer, or use "smart pointers" that clean up after themselves automatically.
Edit: If you actually meant you were creating a static object, by declaring it with the static keyword inside a function, then the answer is different. A static object, once constructed by the first execution of the function that declares it, continues to live until the program ends. Its data members, including pointers, will remain valid. Subsequent calls to the function will access the same object. If the object has allocated any memory, it will remain allocated unless something explicitly deletes it.
The pointer gets destroyed with the rest of your object. Whatever it was pointing at isn't affected at all (unless the object's destructor does something with it).
Revised answer
There are two properties of a variable which are relevant here - scope and lifetime - and I think the question is conflating the two.
In all the contexts I can think of, a statically allocated object has a lifetime that is essentially the lifetime of the process. There are some technical details about exactly when the object is first initialized (constructed), but the net result is essentially the same - a statically allocated object exists for the duration of the process.
However, an object may come into scope, and go out of scope, as the thread of control moves between functions in the program. The scope of the object is where it is visible by name. It may be accessible elsewhere if a pointer to it (or reference to it) is passed to other functions where it would not otherwise be in scope.
Since a statically allocated object has a lifetime of the duration of the program, pointer members of that object do not change because the object goes out of scope; the object continues to exist unchanged, and the pointer members continue to point to the same place. Clearly, if a pointer in the statically allocated object points to a variable that had automatic duration and that pointed-to variable ceases to exist because it is destroyed, then the pointer in the statically allocated object points to an invalid location.
However, the key point is that the statically allocated object is not changed, and the pointer members are not changed, but changes in scope. And there are no leaks caused by the changes in scope.
Original answer
In all the contexts I can think of, a statically allocated object can't go out of scope, pretty much by definition. I suppose that if a shared library was loaded and then unloaded, then a statically allocated object might go 'out of scope', but otherwise...
If this premise is correct, then the second half of the question is easy. You can take either of two views:
Since the static object never goes out of scope, nothing happens to the static object and its pointer member, and it will be pointing to the same place when the object comes back into scope - where scope here means 'into a function that could access the static object'.
When the thread of control leaves a scope that could access the static object, nothing happens to the static object and its pointer member, and it will be pointing to the same place when the object next comes back into scope.
Which is basically saying the same thing, twice. If I said it a third time, it would automatically be true, wouldn't it? So, a statically allocated object doesn't go out of scope (even if it is not always accessible from the current function) and so nothing happens to the pointer members. There...what I said is so. I think!
What am I missing? Does 'statically created object' have a meaning I've not thought of?