I have a std::stack which has some pointers inside:
std::stack<State*> m_states;
When I initialize my program, I call new to push an item onto the stack (it must be a pointer because I will use polymorphic types).
Is this the correct way of deleting with all the stuff?
Here is where I call new (GameState and MenuStatesare classes inherited fromState`):
m_states.push(new GameState());
m_states.push(new MenuState());
And this is what I have in the destructor of the whole App class:
while (!m_states.empty())
{
delete m_states.top(); // (*)
m_states.pop();
}
Should I only call (*), or do I need to pop() as well?
Should I only call (*) or do I need to pop as well?
Well, if you don't call pop() in the while loop, then how will that loop ever end? In other words, how will the condition, !m_states.empty() ever become false?
There are other container types (like std::vector) where you could just run through each member, deleting the pointed-to object, and then clear the container, but you can't do that with the std::stack container. That is to say, there is no [] operator for a stack – you can only access the top element.
Related
I have some legacy code where a Object is dynamically allocated and then emitted:
QList<MyClass *> *list = new QList<MyClass *>();
...
emit listReady(*row);
void OtherClass::slotList(QList<MyClass> list) {
...
delete list???
}
i can delete the objects in the list and i can clear the List, is it possible to delete the list itsef in my slot?
is it possible to delete the list itsef in my slot?
No, it's not possible. Because your slot accept the list by value, which is copy of original QList<MyClass *> *list object.
void OtherClass::slotList(QList<MyClass> list)
To be able delete the list object you should change the slotList arguments to accept the pointer to list.
Not in the way you wrote it. list the parameter is passed by value, so it's a copy of the list to which the pointer list points (it might help clarity of your question if you gave the two variables distinct names).
Even if you changed slotList to take its parameter by reference (slotList(QList<MyClass> &list)), it would still not be a good idea to delete &list inside. That's because it Qt, some signal-slot connections (such as queued connections or connections across threads) do not operate directly on the signal's parameters, but on their copies.
If, for some reason, you need to propagate ownership of the list from the creator signal to the slot and delete it there, you must change the slot to accept a pointer instead:
QList<MyClass *> *row = new QList<MyClass *>();
...
emit listReady(row);
void OtherClass::slotList(QList<MyClass> *list) {
...
delete list;
}
However, the most important question is: why are you actually allocating the QList dynamically in the first place? Containers (like QList) very rarely require dynamic allocation. That holds even more for Qt containers which are implemented with implicit sharing and copy-on-write, so even copying a QList is cheap (it does not copy its contents). The correct solution for you is therefore most likely to have row be an object instead of a pointer, and forget the entire new/delete business.
No, it's not possible, as list is not (the same) pointer nor reference to *list (in which case you could delete &list; (yes, a dirty hack) - only in case of direct connection) and is passed by value instead.
Why are you dynamically allocating the list in the first place?
Say we have the following code:
void foo()
{
Point newpoint(...);
dq.push_back(newpoint);
...
return dq;
}
Suppose dq is deque, Point is some class.
in C, when foo() ends, then newpoint is gone and if it was passed to an array for example, it would've become garbage, but I see that in c++, dq actually keeps it when it's out of foo()'s scope, did it actually invoke a copy constructor on newpoint? What really happens to newpoint? and is this a feature of STL containers or C++'s constructors?
did it actually invoke a copy constructor on newpoint?
Yes.
and is this a feature of STL containers or C++'s constructors?
A STL container with element type T always contains T objects, rather than pointer-to-T or reference-to-T. When initializing an object of type T from an expression of type T, a copy or move is performed.
If you used deque<reference_wraper<Point>> instead then the deque would contain references to Point rather than Point objects, and no copies of Point would occur. It is good that you already understand how this would cause problems.
As you can see push_back will either copy the element or move the element into the container. This original Point goes out of scope at the end of the function but the container isn't storing a reference to this temporary so it's fine.
I have a priority queue inside my class, like this:
class Foo
{
public:
//public methods...
private:
std::priority_queue<Obj, std::vector<Obj>, object_less> foo_queue;
//private methods and members...
}
And I've been using the emplace() method to insert objects inside my priority_queue, like this:
void Foo::add( ... ) {
foo_queue.emplace(var1, var2);
}
And that will call the constructor of Obj(var1,var2) and insert it into the priority queue.
But now, I need to have access to the std::vector<Obj> from outside. From my Obj objects.
Something like creating an Foo object, and changing member that lives inside an object on the priority_queue:
Foo myFoo; // <-- this is where the priority_queue is!
Obj myObj(1); //Creating an object that has some member with value '1'
myFoo.add(myObj); //This will add the object to the priority_queue via emplace (actually it is creating a new object...and not using that one)
myObj.m_member = 2; //HERE WON'T WORK!!! And now I want to change some value on my Obj to '2'. It won't work, because the object that lives inside the priority_queue is different from this one!
So, I was thinking of :
Instead of using the emplace method, use the push (maybe the push won't create a new object)
Changing the priority_queue to, instead of having a vector of objects std::vector<Obj> having a vector of shared pointers, so I can have access to the Obj that it is inside of the priority_queue from outside..as shown above.
QUESTION:
Do you think this is a good idea? I'm a newbie in smart_pointers.. I don't know if there is an easier solution for this.
How can I use a priority_queue with a vector of shared_pointers?
Anyone knows a simple example I can follow?
Something like this:
std::priority_queue<std::shared_ptr<Obj>, std::vector<std::shared_ptr<Obj>>, object_less> foo_queue;
And then hopefully, I can execute:
Foo myFoo;
Obj myObj(1);
myFoo.add(myObj);
myObj.m_member = 2; //<--Now the m_member should be 2 inside the priority_queue.. is this "possible"?
There's nothing wrong with having a priority queue of shared_ptrs. The one thing you'll need to look out for is the comparison. priority_queue needs a comparison, of course, and by default it uses operator <. But that operator, on shared_ptrs, compares the pointers themselves instead of the pointed-to objects. You'll need to pass a custom comparator to the priority queue which operates on the objects themselves. Luckily it looks like you're already using a custom comparator, so the compiler will yell at you if you forget to do that (though the error message may be exceedingly arcane).
One other caveat: If you modify the object in a way that affects its ordering within the priority queue, stuff will go wrong. The only way to do this through the priority_queue interface is to remove the element from the queue, change it, and re-add it.
Suppose that I have a class Foo defined as follows.
If I don't have bars.clear() in ~Foo(), will this result in memory leaks?
I was wondering about this because bars is an object field ( not a pointer field ) so when ~Foo() is called, the destructor of std::vector should be automatically called so I was wondering whether the destructor of std::vector will transparently call .clear() or not.
class Foo
{
private:
std::vector<Bar*> bars;//object field
...
};
Foo::~Foo
{
//bars.clear();
}
std::vector::clear() delete the objects within std::vector and change its std::vector::size() to zero. If you create std::vector, RAII will take care resource release process but you have to wait until reach the out of scope of the vector. If before going out of scope, you need to clean up your vector you can use std::vector::clear().
But in your special case you are keeping pointer to objects inside std::vector, so RAII do delete the pointer but ignores the objects pointing to the pointer. So you have to do your own clean up for the objects pointing to the pointer either before going out of scope and RAII become active or before calling std::vector::clear()
clear() just resets the vector to size 0. It does not delete anything, if the Bar* in the vector bars need to be deleted, you have to do it yourself.
If you hope to protect yourself against memory leaks by calling the clear() method, then I have to disappoint you. If you use a vector with pointers you need to do something like this:
std::vector<Bar*> bars;
bars.push_back(new Bar());
// some work with bars
// ....
// end of bars usage:
// (probably inside ~Foo() )
for(int i=0; i<bars.size(); i++) delete bars[i];
Depending on your level of experience and your specific use-case you might be better of using:
std::vector<Bar> bars;
If you want to know whether the std::vector<...>::clear() method is called from within the destructor of the vector, then the answer is: Maybe but not necessarily and it really doesn't matter anyway.
If you're really curious, you might be able to check, what a destructor of a container class does by looking at the header file for the vector container template. If and how much implementation details of std library objects are visible to the user is highly dependant on the system you're running with. At work I happen to work on Solaris 10 machines. The std lib on those machines is an implementation from Hewlett Packard anno 1994, where a lot of the actual code used by the vector template is still visible:
~vector ()
{
__destroy(__start, __finish);
__value_alloc_type va(__end_of_storage);
va.deallocate(__start,__end_of_storage.data()-__start);
}
void clear()
{
erase(begin(),end());
}
iterator erase (iterator first, iterator last)
{
iterator i = copy(last, end(), first);
iterator tmp = __finish;
__finish = __finish - (last - first);
__destroy(i, tmp);
return first;
}
gameObjects is a std::map<sf::String,VisibleGameObject*>, and results is a std::map<sf::String,VisibleGameObject*>::iterator. When this runs:
return gameObjects.erase(results);
I expected the destructor of VisibleGameObject to run, which is:
VisibleGameObject::~VisibleGameObject(){
m_pSceneManager->removeSprite(name);
}
never runs, until the class which holds gameObjects is destroyed, which then runs:
GameObjectManager::~GameObjectManager(){
std::for_each(gameObjects.begin(),gameObjects.end(),GameObjectDeallocator());
}
struct GameObjectDeallocator{
void operator()(const std::pair<sf::String,VisibleGameObject*>&p) const{
delete p.second;
}
};
then it does run. Why doesn't it run in the first case?
Using SFML 2.0
Thanks
erase removes the pointers from the container, but does not call delete.
Suggestion:
change your map to simply be:
std::map<sf::String,VisibleGameObject>
i.e. objects not pointers to them
or:
use a shared_ptr/unique_ptr (e.g. boost::shared_ptr or std::shared_ptr depending upon availability):
std::map<sf::String,std::shared_ptr<VisibleGameObject> >
which will call the destructor
calling erase() won't free the pointer as the implementation(map) doesn't know how the object pointed to was allocated ((example: should it call delete or free?) and more importantly it doesn't own the pointer i.e you don't transfer ownership to the container when storing pointers.
Use std::unique_ptr to wrap you pointer and then store it in the container by value. This will aid garbage collection and give you what you need.
using VisibileGameObjectPtr = std::unique_ptr<VisibleGameObject>;
std::map<sf::String,VisibleGameObjectPtr> gameObjects;
// memory will be automatically garbage collected when you erase this item.
gameObject["key"] = VisibileGameObjectPtr(new VisibleGameObject(..args..));