How can I free up memory in a pointer vector?
Here's the code:
class A
{
private:
int x,y,z;
public:
A(param1, param2, param3)
{
x=param1;
y=param2;
z=param3;
}
~A()
{
//prompts an alertbox, warning me about the successful call of the destructor;
}
};
...
vector<A*> list;
list.push_back(new A(1,2,3));
list.erase(list.begin()+index);//SHOULD delete the object from the memory;
list.clear();
I found out that .erase() doesn't free up memory, neither calls the destructor; I tried to use delete on every list entry with an iteration, but crashes after one iteration. Already checked if the list entry was already NULL, to avoid any error.
Am I missing something?
Also, I must use only STL, don't need Boost.
list.erase will deallocate the memory for its member elements (and call their destructors, if they exist); it will not call delete on them.
A Boost shared_ptr would be the obvious way of doing this. If you don't want to use that, you're either going to write your own smart-pointer class, or iterate through list and call delete on each pointer before calling erase. You can do this neatly with something like:
void my_delete(A *p)
{
delete p;
}
...
std::for_each(list.begin(), list.end(), my_delete);
for( std::vector<A*>::iterator i = list.begin(), endI = list.end(); i != endI; ++i)
{
delete *i;
}
list.clear();
or, using new lambda functions
std::for_each( list.begin(), list.end(), []( A* element) { delete element; });
list.clear();
erase only erases what's in the vector (the pointers) without doing anything about what they might point at.
If you want what the point at deleted, you need to handle that yourself.
My advice would be to avoid handling any of this yourself, and consider using Boost ptr_vector instead.
Upon destruction, an STL container will destroy the objects it contains. If those objects are pointers, then it will destroy the pointers. For naked, dumb pointers, this will not delete the objects they point to. That's why it is usually best to use smart pointers for that. Smart pointers will delete the objects they refer to upon deletion; std::shared_ptr keeps track of copying pointers and how many references to a given object exist, and will only delete the object when the last pointer dies. This is always a good first candidate when looking for a suiting smart pointer. Your container would then be declared like this: std::vector< std::shared_ptr<A> >
However, your compiler/std lib might not come with std::shared_ptr, which is a feature of the next C++ standard, generally expected next year. It might, however, come with std::tr1::shared_ptr, which is a TR1 feature from 2003. (If all else fails, boost has boost_shared_ptr, but you already ruled out boost.)
You can manually manage dynamically allocated objects in STL containers, but it's a burden and prone to errors. For example, you must prevent functions from returning early (before the manual cleanup) through return statements or exceptions, and you must watch out for copy operations on containers. (Otherwise two containers would have pointers referring to the same objects, which you might then try to destroy twice.)
Manually managing resources is a PITA, prone to errors, and best avoided.
The code you have posted is not legitimate C++. Plus, erase does not delete objects you have allocated, it only erases contents of the vector, which in your case are pointers. The actual objects that you have allocated are not being deleted. Here is a correct way of doing what you want:
#include <vector>
#include <algorithm>
class A
{
int x,y,z;
public:
A (int param1, int param2, int param3) :
x (param1), y (param2), z (param3)
{
}
};
struct Deleter
{
template <typename T>
void operator () (T *obj) const
{
delete obj;
}
};
int
main ()
{
std::vector<A*> list;
list.push_back (new A (1, 2, 3));
list.push_back (new A (4, 5, 6));
list.push_back (new A (7, 8, 9));
std::for_each (list.begin (), list.end (), Deleter ());
list.clear ();
}
You may also look at Boost Ptr Container library that solves this problem in a safe and reusable manner. In C++0x, there is a std::unique_ptr template class that supports movable semantics and can be used with STL containers and algorithms to clean up memory automatically.
for(size_t i = 0; i < list.size(); ++i)
{
delete list[i];
}
list.clear();
If your make something like this and your code crashes, post exact code and crash information.
Related
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;
}
does the function set::insert saves a pointer to the element or a copy of it. meaning, can I do the following code, or I have to make sure that the pointers are not deleted?
int *a;
*a=new int(1);
set<int> _set;
_set.insert (*a);
delete a;
*a=new int(2);
_set.insert (*a);
delete a;
I gave the example with int, but my real program uses classes that I created.
All STL containers store a copy of the inserted data. Look here in section "Description" in the third paragraph: A Container (and std::set models a Container) owns its elements. And for more details look at the following footnote [1]. In particular for the std::set look here under the section "Type requirements". The Key must be Assignable.
Apart from that you can test this easily:
struct tester {
tester(int value) : value(value) { }
tester(const tester& t) : value(t.value) {
std::cout << "Copy construction!" << std::endl;
}
int value;
};
// In order to use tester with a set:
bool operator < (const tester& t, const tester& t2) {
return t.value < t2.value;
}
int main() {
tester t(2);
std::vector<tester> v;
v.push_back(t);
std::set<tester> s;
s.insert(t);
}
You'll always see Copy construction!.
If you really want to store something like a reference to an object you either can store pointers to these objects:
tester* t = new tester(10);
{
std::set<tester*> s;
s.insert(t);
// do something awesome with s
} // here s goes out of scope just as well the contained objects
// i.e. the *pointers* to tester objects. The referenced objects
// still exist and thus we must delete them at the end of the day:
delete t;
But in this case you have to take care of deleting the objects correctly and this is sometimes very difficult. For example exceptions can change the path of execution dramatically and you never reach the right delete.
Or you can use smart pointers like boost::shared_ptr:
{
std::set< boost::shared_ptr<tester> > s;
s.insert(boost::shared_ptr<tester>(new tester(20)));
// do something awesome with your set
} // here s goes out of scope and destructs all its contents,
// i.e. the smart_ptr<tester> objects. But this doesn't mean
// the referenced objects will be deleted.
Now the smart pointers takes care for you and delete their referenced objects at the right time. If you copied one of the inserted smart pointers and transfered it somewhere else the commonly referenced object won't be delete until the last smart pointer referencing this object goes out of scope.
Oh and by the way: Never use std::auto_ptrs as elements in the standard containers. Their strange copy semantics aren't compatible with the way the containers are storing and managing their data and how the standard algorithms are manipulating them. I'm sure there are many questions here on StackOverflow concerning this precarious issue.
std::set will copy the element you insert.
You are saving pointers into the set.
The object pointed at by the pointer is not copied.
Thus after calling delete the pointer in the set is invalid.
Note: You probably want to just save integers.
int a(1);
set<int> s;
s.insert(a); // pushes 1 into the set
s.insert(2); // pushes 2 into the set.
Couple of other notes:
Be careful with underscores at the beginning of identifier names.
Use smart pointers to hold pointers.
Ptr:
std::auto_ptr<int> a(new int(1));
set<int*> s;
s.insert(a.release());
// Note. Set now holds a RAW pointer that you should delete before the set goes away.
// Or convert into a boost::ptr_set<int> so it takes ownership of the pointer.
int *a;
*a=new int(1);
This code is wrong because you try to use the value stored at address a which is a garbage.
And, every stl containers copy elements unless you use move semantics with insert() and push_back() taking rvalue references in C++0x.
Hi I asked a question today about How to insert different types of objects in the same vector array and my code in that question was
gate* G[1000];
G[0] = new ANDgate() ;
G[1] = new ORgate;
//gate is a class inherited by ANDgate and ORgate classes
class gate
{
.....
......
virtual void Run()
{ //A virtual function
}
};
class ANDgate :public gate
{.....
.......
void Run()
{
//AND version of Run
}
};
class ORgate :public gate
{.....
.......
void Run()
{
//OR version of Run
}
};
//Running the simulator using overloading concept
for(...;...;..)
{
G[i]->Run() ; //will run perfectly the right Run for the right Gate type
}
and I wanted to use vectors so someone wrote that I should do that :
std::vector<gate*> G;
G.push_back(new ANDgate);
G.push_back(new ORgate);
for(unsigned i=0;i<G.size();++i)
{
G[i]->Run();
}
but then he and many others suggested that I would better use Boost pointer containers
or shared_ptr. I have spent the last 3 hours reading about this topic, but the documentation seems pretty advanced to me . ****Can anyone give me a small code example of shared_ptr usage and why they suggested using shared_ptr. Also are there other types like ptr_vector, ptr_list and ptr_deque** **
Edit1: I have read a code example too that included:
typedef boost::shared_ptr<Foo> FooPtr;
.......
int main()
{
std::vector<FooPtr> foo_vector;
........
FooPtr foo_ptr( new Foo( 2 ) );
foo_vector.push_back( foo_ptr );
...........
}
And I don't understand the syntax!
Using a vector of shared_ptr removes the possibility of leaking memory because you forgot to walk the vector and call delete on each element. Let's walk through a slightly modified version of the example line-by-line.
typedef boost::shared_ptr<gate> gate_ptr;
Create an alias for the shared pointer type. This avoids the ugliness in the C++ language that results from typing std::vector<boost::shared_ptr<gate> > and forgetting the space between the closing greater-than signs.
std::vector<gate_ptr> vec;
Creates an empty vector of boost::shared_ptr<gate> objects.
gate_ptr ptr(new ANDgate);
Allocate a new ANDgate instance and store it into a shared_ptr. The reason for doing this separately is to prevent a problem that can occur if an operation throws. This isn't possible in this example. The Boost shared_ptr "Best Practices" explain why it is a best practice to allocate into a free-standing object instead of a temporary.
vec.push_back(ptr);
This creates a new shared pointer in the vector and copies ptr into it. The reference counting in the guts of shared_ptr ensures that the allocated object inside of ptr is safely transferred into the vector.
What is not explained is that the destructor for shared_ptr<gate> ensures that the allocated memory is deleted. This is where the memory leak is avoided. The destructor for std::vector<T> ensures that the destructor for T is called for every element stored in the vector. However, the destructor for a pointer (e.g., gate*) does not delete the memory that you had allocated. That is what you are trying to avoid by using shared_ptr or ptr_vector.
I will add that one of the important things about shared_ptr's is to only ever construct them with the following syntax:
shared_ptr<Type>(new Type(...));
This way, the "real" pointer to Type is anonymous to your scope, and held only by the shared pointer. Thus it will be impossible for you to accidentally use this "real" pointer. In other words, never do this:
Type* t_ptr = new Type(...);
shared_ptr<Type> t_sptr ptrT(t_ptr);
//t_ptr is still hanging around! Don't use it!
Although this will work, you now have a Type* pointer (t_ptr) in your function which lives outside the shared pointer. It's dangerous to use t_ptr anywhere, because you never know when the shared pointer which holds it may destruct it, and you'll segfault.
Same goes for pointers returned to you by other classes. If a class you didn't write hands you a pointer, it's generally not safe to just put it in a shared_ptr. Not unless you're sure that the class is no longer using that object. Because if you do put it in a shared_ptr, and it falls out of scope, the object will get freed when the class may still need it.
Learning to use smart pointers is in my opinion one of the most important steps to become a competent C++ programmer. As you know whenever you new an object at some point you want to delete it.
One issue that arise is that with exceptions it can be very hard to make sure a object is always released just once in all possible execution paths.
This is the reason for RAII: http://en.wikipedia.org/wiki/RAII
Making a helper class with purpose of making sure that an object always deleted once in all execution paths.
Example of a class like this is: std::auto_ptr
But sometimes you like to share objects with other. It should only be deleted when none uses it anymore.
In order to help with that reference counting strategies have been developed but you still need to remember addref and release ref manually. In essence this is the same problem as new/delete.
That's why boost has developed boost::shared_ptr, it's reference counting smart pointer so you can share objects and not leak memory unintentionally.
With the addition of C++ tr1 this is now added to the c++ standard as well but its named std::tr1::shared_ptr<>.
I recommend using the standard shared pointer if possible. ptr_list, ptr_dequeue and so are IIRC specialized containers for pointer types. I ignore them for now.
So we can start from your example:
std::vector<gate*> G;
G.push_back(new ANDgate);
G.push_back(new ORgate);
for(unsigned i=0;i<G.size();++i)
{
G[i]->Run();
}
The problem here is now that whenever G goes out scope we leak the 2 objects added to G. Let's rewrite it to use std::tr1::shared_ptr
// Remember to include <memory> for shared_ptr
// First do an alias for std::tr1::shared_ptr<gate> so we don't have to
// type that in every place. Call it gate_ptr. This is what typedef does.
typedef std::tr1::shared_ptr<gate> gate_ptr;
// gate_ptr is now our "smart" pointer. So let's make a vector out of it.
std::vector<gate_ptr> G;
// these smart_ptrs can't be implicitly created from gate* we have to be explicit about it
// gate_ptr (new ANDgate), it's a good thing:
G.push_back(gate_ptr (new ANDgate));
G.push_back(gate_ptr (new ORgate));
for(unsigned i=0;i<G.size();++i)
{
G[i]->Run();
}
When G goes out of scope the memory is automatically reclaimed.
As an exercise which I plagued newcomers in my team with is asking them to write their own smart pointer class. Then after you are done discard the class immedietly and never use it again. Hopefully you acquired crucial knowledge on how a smart pointer works under the hood. There's no magic really.
The boost documentation provides a pretty good start example:
shared_ptr example (it's actually about a vector of smart pointers) or
shared_ptr doc
The following answer by Johannes Schaub explains the boost smart pointers pretty well:
smart pointers explained
The idea behind(in as few words as possible) ptr_vector is that it handles the deallocation of memory behind the stored pointers for you: let's say you have a vector of pointers as in your example. When quitting the application or leaving the scope in which the vector is defined you'll have to clean up after yourself(you've dynamically allocated ANDgate and ORgate) but just clearing the vector won't do it because the vector is storing the pointers and not the actual objects(it won't destroy but what it contains).
// if you just do
G.clear() // will clear the vector but you'll be left with 2 memory leaks
...
// to properly clean the vector and the objects behind it
for (std::vector<gate*>::iterator it = G.begin(); it != G.end(); it++)
{
delete (*it);
}
boost::ptr_vector<> will handle the above for you - meaning it will deallocate the memory behind the pointers it stores.
Through Boost you can do it
>
std::vector<boost::any> vecobj;
boost::shared_ptr<string> sharedString1(new string("abcdxyz!"));
boost::shared_ptr<int> sharedint1(new int(10));
vecobj.push_back(sharedString1);
vecobj.push_back(sharedint1);
>
for inserting different object type in your vector container. while for accessing you have to use any_cast, which works like dynamic_cast, hopes it will work for your need.
#include <memory>
#include <iostream>
class SharedMemory {
public:
SharedMemory(int* x):_capture(x){}
int* get() { return (_capture.get()); }
protected:
std::shared_ptr<int> _capture;
};
int main(int , char**){
SharedMemory *_obj1= new SharedMemory(new int(10));
SharedMemory *_obj2 = new SharedMemory(*_obj1);
std::cout << " _obj1: " << *_obj1->get() << " _obj2: " << *_obj2->get()
<< std::endl;
delete _obj2;
std::cout << " _obj1: " << *_obj1->get() << std::endl;
delete _obj1;
std::cout << " done " << std::endl;
}
This is an example of shared_ptr in action. _obj2 was deleted but pointer is still valid.
output is,
./test
_obj1: 10 _obj2: 10
_obj2: 10
done
The best way to add different objects into same container is to use make_shared, vector, and range based loop and you will have a nice, clean and "readable" code!
typedef std::shared_ptr<gate> Ptr
vector<Ptr> myConatiner;
auto andGate = std::make_shared<ANDgate>();
myConatiner.push_back(andGate );
auto orGate= std::make_shared<ORgate>();
myConatiner.push_back(orGate);
for (auto& element : myConatiner)
element->run();
Suppose I have a std::vector<Obj *> objs (for performance reasons I have pointers not actual Objs).
I populate it with obj.push_back(new Obj(...)); repeatedly.
After I am done, I have to delete the pushed-back elements. One way is to do this:
for (std::vector<Obj *>::iterator it = objs.begin(); it != objs.end(); ++it) {
delete *it;
}
However, I am interested if I can use for_each algorithm to do the same:
#include <algorithm>
...
for_each(objs.begin(), objs.end(), delete);
What do you think?
Your problem is that delete is not a function, but rather a keyword and as such you can't take it's address.
In C++0x, there will be a std::default_delete class (used by std::unique_ptr), which you could use, or - as everyone's saying - writing one yourself would be trivial (the standard one also raises a compile error, if you try to delete an incomplete type).
#include <vector>
#include <algorithm>
#include <memory>
int main()
{
std::vector<int*> vec;
std::for_each(vec.begin(), vec.end(), std::default_delete<int>());
}
Yes, but you need a functor:
struct delete_ptr
{
template <typename T>
void operator()(T* pPtr)
{
delete pPtr;
}
};
std::for_each(objs.begin(), objs.end(), delete_ptr());
In C++0x, lambda's help you make functors in-place:
std::for_each(objs.begin(), objs.end(), [](Obj* pPtr){ delete pPtr; });
However, this is dangerous, in the face of exceptions. sbi has shown a solution.
While you can do this (GMan has shown a solution), having containers with naked pointers to owned resources is a strong code smell. For example, in this code:
void foo()
{
std::vector<Obj *> bar;
fill(bar);
use(bar);
std::for_each(objs.begin(), objs.end(), delete_ptr()); // as GMan suggests
}
if use() throws, you'll leak objects.
So it's better to use smart pointers for this:
std::vector< std::shared_ptr<Obj> > bar;
Not exactly; for_each requires a function or object that can be invoked with (), and delete is neither a function nor an object. You will have to wrap it up in a function (or function object), perhaps like:
struct Deleter
{
void operator()(Obj* obj) {delete obj;}
};
std::for_each(objs.begin(), objs.end(), Deleter());
But you should be very careful managing object lifetimes with raw pointers, especially if you're passing them around. You'll need to remember to delete them if you erase them from the vector, or reassign them, or if you clear the vector, or if an exception, break or function return might cause the vector to be destroyed. In general, it's always better to separate the responsibilities of resource management and resource usage.
You'd be better off with a vector of objects, unless Obj is a polymorphic base class, or the objects really are big or complicated enough that copying them will have a noticeable impact on performance. If that is the case (and you've profiled it to be sure that it's the case), you should consider a vector of smart pointers (shared_ptr, or unique_ptr if your compiler supports it), or Boost's ptr_vector.
Getting in the habit of using automatic resource management classes will save you a lot of headaches in the future.
Instead of trying to solve the deletion problem, you can make it go away completely by storing shared_ptrs in the vector, or by using boost's ptr_vector (see http://www.boost.org/doc/libs/1_39_0/libs/ptr_container/doc/tutorial.html).
for_each needs a function pointer or function object. For memory deallocation you could try &::operator delete, which would take the address of the function that deallocates memory. However, when you use the delete statement the compiler calls the destructor before calling operator delete(void*) so cleanup is actually not part of the operator delete(void*) function.
Use a functor ala GMan's answer.
Yes. Fill it with smart pointers and use vector.clear() is the easiest way.
I tried this:
....
vector<players*> player;
for (int i = 0; i<10; i++)
{
player.push_back(new players());
}
...
And I wonder if I need to free memory for the vector? If so, how?
If you need to store pointers to things in a container, you should either store some sort of smart pointer (like std::tr1::shared_ptr or boost::shared_ptr) or use a container designed for storing pointers, like those found in the Boost Pointer Container Library.
If you do store bare pointers, you need to remember to delete the pointers in the container before the container is destroyed. This includes any time that an exception is thrown that might cause the container to be destroyed. Getting this right is tedious, bug-prone, and wholly unnecessary given the facilities mentioned in the previous paragraph.
Yes, you do need to delete them yourself. The vector is only going to "destruct" the pointers (which does nothing).
If you can, use the Boost pointer containers library, and you won't have to worry about it. However, if you can't you need to wrap the container up. Consider an exception is thrown between the time the container is populated and the time its elements are deleted. You will not execute the element delete code and leak.
A simple wrapper might look like:
struct default_deleter
{
template <typename T>
void operator()(T* pPtr)
{
delete pPtr;
}
};
template <typename T, typename Deleter = default_deleter>
struct container_wrapper
{
typedef T container_type;
typedef Deleter deleter_type;
container_wrapper(container_type pContainer = container_type()) :
container(pContainer)
{}
~container_wrapper(void)
{
std::for_each(container.begin(), container.end(), deleter_type());
}
container_type container;
};
Use it like:
typedef std::vector<int*> vec_intptr;
typedef container_wrapper<vec_intptr> vec;
vec v;
v.container.push_back(new int); // and never worry about it again
This is a simple wrapper. Any pop_back(), erase(), etc. operations will have the wrong effect. I strongly suggest using Boost.
One may think of using a container of auto_ptr. Contrarily, this is a bad idea; the copy-semantics of an auto_ptr prevent it from working. The best option is to get rid of the dynamic allocation, if possible.
since you are creating new players(), you will have to delete them. probably best to iterate through the vector deleting the players and then clean up your vector.