This question already has answers here:
C++: Replace raw pointers with shared and weak ptr
(4 answers)
Replacing existing raw pointers with smart pointers
(5 answers)
Closed 4 years ago.
I'm trying to understand how can I substitute raw pointers on my C++ software with smart-pointers.
I have the following code:
class Foo
{
private:
std::vector<Bar *> m_member;
};
Now in some function I populate that vector with:
m_member.push_back( new Bar() );
and when my program finishes I delete the memory with:
for( std::vector<Bar *>::iterator it = m_member.begin(); it < m_member.end(); ++it )
{
delete (*it);
(*it) = NULL;
}
Now all this is good.
The problem is as I see it comes from the fact that at one point of time I may need to delete one of the member from the vector (this member is user-specified).
Now this is easy:
for(...)
{
if( (*it)->GetFieldFromBar() == <user_specified_condition> )
{
delete (*it);
(*it) = NULL;
}
}
But how do I re-write it with the smart pointers? Is it even possible?
It's actually far easier with smart pointers, and here unique_ptr.
Population is done through:
m_member.push_back(std::make_unique<Bar>()); // C++14, you can use std::unique_ptr<Bar>(new Bar) is you only have C++11
No need for a destructor.
For custom deletion:
for(auto& p: m_member)
{
if( p->GetFieldFromBar() == <user_specified_condition> )
{
p.reset();
}
}
Yes, using std::vector<std::unique_ptr<Bar>> is ideal in this case. You clearly have ownership in the vector.
Adding elements to it can be done the following in c++14:
m_member.push_back( std::make_unique<Bar>() );
Removing all elements gets reduced to: m_member.clear() or even just letting it go out of scope.
Selectively removing the elements is better done like:
m_member.erase(std::remove_if(m_member.begin(), m_member.end(), [&](auto &&ptr) { return ptr->GetFieldFromBar() == <user_specified_condition>; }), m_member.end());
A bit descriptive for dealing with all elements, though, you can wrap it in a function to get rid of the boiler plate.
Related
Well I am creating a vector like this
vector<Member*> emp;
Then I am creating heap objects of the member class like this
Member* memObj = new Member();
Then using push_back like this
emp.push_back(memObj);
Well after using all my functions do I have to clear the memory by iterating like this ?
for( vector<Member*>::iterator iter = emp.begin();
iter != emp.end(); )
{
Member* mem = *iter;
iter = emp.erase (iter);
delete mem;
//iter++;
}
Is there any effective way other than iterating through each value? clear function calls the destructor only and it clears the values but does not free the memory..I wish to achieve polymorphism here...I am new in C++ ....please help..Thanks in advance.. :) I am not using C++11
If you are able to use a C++11 compiler, you can use one of the smart pointers.
std::unique_ptr
std::vector<std::unique_ptr<Member>> emp;
or
std::shared_ptr
std::vector<std::shared_ptr<Member>> emp;
EDIT
If you are not able to use a C++11 compiler, VS 2005 is definitely too old to support C++11, you will have to delete the objects manually, like you have shown.
However, I would add a helper class to help with deleteing the Member objects.
struct MemberDeleteHelper
{
MemberDeleteHelper(std::vector<Member*> emp) : emp_(emp);
~MemberDeleteHelper()
{
for( vector<Member*>::iterator iter = emp.begin();
iter != emp.end(); ++iter )
{
delete *iter;
}
}
std::vector<Member*>& emp_;
};
and use it as:
vector<Member*> emp;
MemberDeleteHelper deleteHelper(emp);
With this in place, the elements of emp will be deleted no matter how you return from the function. If an exception gets thrown from a nested function call, the stack will be unrolled and the elements of emp will still be deleted.
EDIT 2
Do not use auto_ptr objects in std::vector. The pitfalls of using auto_ptr in STL containers are discussed at http://www.devx.com/tips/Tip/13606 (Thanks are due to #pstrjds for the link).
Unless your intent is to added instances of types derived from Member to the vector, there's no need for vector<Member*>, just use vector<Member>.
If you actually need dynamic allocation, use vector<unique_ptr<Member>>. The smart pointer will automatically delete the instances when you clear() the vector. If this is the case, don't forget that Member needs a virtual destructor.
Similar options for pre-C++11 compilers are std::vector<std::tr1::shared_ptr<Member>> or boost::ptr_vector<Member>.
Finally, your current code has a bug. vector::erase returns a pointer to the next element, so by manually incrementing the iterator within the loop, you're skipping every other element. And I don't understand why you're going through the trouble of storing the pointer in a temporary variable. Your loop should be
for( vector<Member*>::iterator iter = emp.begin(); iter != emp.end(); )
{
delete *iter;
iter = emp.erase(iter);
}
or just delete all the elements first and then clear the vector
for( vector<Member*>::iterator iter = emp.begin(); iter != emp.end(); ++iter)
{
delete *iter;
}
emp.clear();
This question already has answers here:
How to delete an element from a vector while looping over it?
(6 answers)
Closed 9 years ago.
I use a vector of shared pointers to contain some game characters called customer.
typedef std::shared_ptr<Customer> customer;
std::vector<customer> customers;
customers.push_back(customer(new Customer()));
for(int i = 0; i < customers.size(); i++)
{
if(customers[i]->hasLeftScreen())
{
if(!customers[i]->itemRecieved())
outOfStocks++;
// Kill Character Here
}
}
I have used vectors to hold objects before so am used to calling erase on the vector and passing in the iterator. My question is there a way of deleting a the pointer from the vector in the above code snippet? I was hoping not to use an iterator here to simplify the code. I also need to delete the pointer because I was the customer to be removed from the game once it has left the screen.
Many thanks
Consider using an iterator, which frankly will be much easier to deal with. I'm not sure of your aversion to them, but see below:
std::vector<customer>::iterator it = customers.begin();
while (it != customers.end())
{
if(it->hasLeftScreen())
{
if(!it->itemRecieved())
outOfStocks++;
it = customers.erase(it);
continue;
}
++it;
}
This will remove the shared pointer instance from the vector. If the instance is the last reference to the shared pointer it will also release the associated memory of said Customer, firing its destructor, etc... (somewhat the point of using smart shared pointers in the first place, and props for using smart pointers, by the way).
You should always use iterators; it's a C++ idiom. This would change the code to...
for(auto i = customers.begin(); i != customers.end(); ++i)
{
if((*i)->hasLeftScreen())
{
if(!(*i)->itemRecieved())
outOfStocks++;
// Kill Character Here
}
}
Now, it is clear, we use the erase-remove idiom instead.
int outOfStocks = 0;
auto it = std::remove_if(customer.begin(), customers.end(), [&](Customer const& i) {
if(i->hasLeftScreen()) {
if(!i->itemRecieved()) {
outOfStocks++;
}
return true;
}
return false;
}
std::erase(it, customers.end());
You can also take advantage of "iterator arithmetic":
// Kill Character Here
customers.erase(customers.begin() + i);
... but that has a problem that customers.size() and the current index will get invalidated as the container will shrink.
Also, you don't need to explicitly delete the customer you're removing, because the smart pointer will take care of that.
Here's my code for updating a list of items in a vector and removing some of them:
std::vector<Particle*> particles;
...
int i = 0;
while ( i < particles.size() ) {
bool shouldRemove = particles[ i ]->update();
if ( shouldRemove ) {
delete particles[ i ];
particles[ i ] = particles.back();
particles.pop_back();
} else {
i++;
}
}
When I find an item that should be removed, I replace it with the last item from the vector to avoid potentially copying the rest of the backing array multiple times. Yes, I know it is premature optimization...
Is this a valid way of removing items from the vector? I get some occasional (!) crashes somewhere around this area but can't track them down precisely (LLDB fails to show me the line), so I would like to make sure this part is OK. Or is it... ?
UPDATE: I found the bug and indeed it was in another part of my code.
Yes, this is a valid way. But if it is not a performance bottleneck in your program then it's better to use smart pointers to manage the lifetime of Particle objects.
Take a look at std::remove_if.
Also, might be good to use a shared pointer as it may make life easier :-)
typedef std::shared_ptr< Particle > ParticlePtr;
auto newend = std::remove_if( particles.begin(), particles.end(), [](ParticlePtr p) {return p->update();} );
particles.erase( newend, particles.end() );
You are iterating over an STL vector, so use iterators, it's what they're for.
std::vector<Particle*>::iterator particle = particles.begin();
while ( particle != particles.end() ) {
bool shouldRemove = particle->update();
if ( shouldRemove ) {
particle = particles.remove(particle); //remove returns the new next particle
} else {
++particle;
}
}
Or, even better, use smart pointers and the erase/remove idiom. Remove_if itself does as you describe, moving old members to the back of the vector and returning an iterator pointing to the first non-valid member. Passing this and the vector's end() to erase allows erase to erase all the old members as they are in a contiguous block. In your scenario, you would have to delete each before calling erase:
auto deleteBegin = std::remove_if(
particles.begin(), particles.end(),
[](Particle* part){ return part->update();}));
for(auto deleteIt = deleteBegin; deleteIt != particles.end(); ++deleteIt)
delete *deleteIt;
std::erase(deleteBegin, particles.end());
Or pre C++11:
bool ShouldDelete(Particle* part) {
return part->update();
}
typedef vector<Particle*> ParticlesPtrVec;
ParticlesPtrVec::iterator deleteBegin = std::remove_if(
particles.begin(), particles.end(), ShouldDelete);
for(ParticlesPtrVec::iterator deleteIt = deleteBegin;
deleteIt != particles.end(); ++deleteIt)
delete *deleteIt;
std::erase(deleteBegin, particles.end());
Then test the whole code for performance and optimise wherever the actual bottlenecks are.
I don't see any direct issue in the code. You are probably having some issues with the actual pointers inside the vector.
Try running valgrind on your code to detect any hidden memory access problems, or switch to smart pointers.
I'm creating an object via new, then later adding the pointer to an std::list once the object is set up.
What is the correct way of deleting a pointer and erasing the data from the list without causing memory leaks?
Instead of manual loop to search the element, I would rather use std::find_if
auto it = std::find_if(lst.begin(),
lst.end(),
[&val](datalist const &d) { return d.index == val; });
if ( it != lst.end() )
{
delete *it;
lst.erase(it);
}
That is not to say that you're doing it incorrectly.
However, your code will improve if you consider using some form of smart points, such as std::unique_ptr, std::shared_ptr, or boost's smart pointers, then you don't have to manage memory yourself.
If you change your std::list to hold datalist instances instead of datalist* pointers, then you don't have to delete the datalist instances manually anymore. When you remove an element from a std::list (or any other STL container, for that matter), the element's data is freed automatically for you. If the element is a class/struct with a destructor defined, the destructor will be called.
Try this:
std::list<datalist> m_DataList;
.
datalist AR; // <-- local variable on the stack, freed when out of scope
AR.index = ...;
AR.number = ...;
mylist.push_back(AR); // <-- pushes a copy-constructed instance of the variable
.
std::list<datalist>::iterator Iter1 = m_DataList.begin();
while(Iter1 != m_DataList.end())
{
if (Iter1->index == m_SomeVar)
{
m_DataList.erase(Iter1); // <-- copied datalist instance is freed automatically
break;
}
++Iter1;
}
What is the shortest chunk of C++ you can come up with to safely clean up a std::vector or std::list of pointers? (assuming you have to call delete on the pointers?)
list<Foo*> foo_list;
I'd rather not use Boost or wrap my pointers with smart pointers.
For std::list<T*> use:
while(!foo.empty()) delete foo.front(), foo.pop_front();
For std::vector<T*> use:
while(!bar.empty()) delete bar.back(), bar.pop_back();
Not sure why i took front instead of back for std::list above. I guess it's the feeling that it's faster. But actually both are constant time :). Anyway wrap it into a function and have fun:
template<typename Container>
void delete_them(Container& c) { while(!c.empty()) delete c.back(), c.pop_back(); }
Since we are throwing down the gauntlet here... "Shortest chunk of C++"
static bool deleteAll( Foo * theElement ) { delete theElement; return true; }
foo_list . remove_if ( deleteAll );
I think we can trust the folks who came up with STL to have efficient algorithms. Why reinvent the wheel?
for(list<Foo*>::const_iterator it = foo_list.begin(); it != foo_list.end(); ++it)
{
delete *it;
}
foo_list.clear();
If you allow C++11, you can do a very short version of Douglas Leeder's answer:
for(auto &it:foo_list) delete it; foo_list.clear();
It's really dangerous to rely on code outside of the container to delete your pointers. What happens when the container is destroyed due to a thrown exception, for example?
I know you said you don't like boost, but please consider the boost pointer containers.
template< typename T >
struct delete_ptr : public std::unary_function<T,bool>
{
bool operator()(T*pT) const { delete pT; return true; }
};
std::for_each(foo_list.begin(), foo_list.end(), delete_ptr<Foo>());
I'm not sure that the functor approach wins for brevity here.
for( list<Foo*>::iterator i = foo_list.begin(); i != foo_list.end(); ++i )
delete *i;
I'd usually advise against this, though. Wrapping the pointers in smart pointers or using a specialist pointer container is, in general, going to be more robust. There are lots of ways that items can be removed from a list ( various flavours of erase, clear, destruction of the list, assignment via an iterator into the list, etc. ). Can you guarantee to catch them all?
The following hack deletes the pointers when your list goes out of scope using RAII or if you call list::clear().
template <typename T>
class Deleter {
public:
Deleter(T* pointer) : pointer_(pointer) { }
Deleter(const Deleter& deleter) {
Deleter* d = const_cast<Deleter*>(&deleter);
pointer_ = d->pointer_;
d->pointer_ = 0;
}
~Deleter() { delete pointer_; }
T* pointer_;
};
Example:
std::list<Deleter<Foo> > foo_list;
foo_list.push_back(new Foo());
foo_list.clear();
At least for a list, iterating and deleting, then calling clear at the end is a bit inneficient since it involves traversing the list twice, when you really only have to do it once. Here is a little better way:
for (list<Foo*>::iterator i = foo_list.begin(), e = foo_list.end(); i != e; )
{
list<Foo*>::iterator tmp(i++);
delete *tmp;
foo_list.erase(tmp);
}
That said, your compiler may be smart enough to loop combine the two anyways, depending on how list::clear is implemented.
Actually, I believe the STD library provides a direct method of managing memory in the form of the allocator class
You can extend the basic allocator's deallocate() method to automatically delete the members of any container.
I /think/ this is the type of thing it's intended for.
for(list<Foo*>::const_iterator it = foo_list.begin(); it != foo_list.end(); it++)
{
delete *it;
}
foo_list.clear();
There's a small reason why you would not want to do this - you're effectively iterating over the list twice.
std::list<>::clear is linear in complexity; it removes and destroys one element at a time within a loop.
Taking the above into consideration the simplest to read solution in my opinion is:
while(!foo_list.empty())
{
delete foo_list.front();
foo_list.pop_front();
}
Since C++11:
std::vector<Type*> v;
...
std::for_each(v.begin(), v.end(), std::default_delete<Type>());
Or, if you are writing templated code and want to avoid specifying a concrete type:
std::for_each(v.begin(), v.end(),
std::default_delete<std::remove_pointer<decltype(v)::value_type>::type>());
Which (since C++14) can be shortened as:
std::for_each(v.begin(), v.end(),
std::default_delete<std::remove_pointer_t<decltype(v)::value_type>>());
void remove(Foo* foo) { delete foo; }
....
for_each( foo_list.begin(), foo_list.end(), remove );
for (list<Foo*>::const_iterator i = foo_list.begin(), e = foo_list.end(); i != e; ++i)
delete *i;
foo_list.clear();
This seems cleanest imo, but your c++ version must support this type of iteration (I believe anything including or ahead of c++0x will work):
for (Object *i : container) delete i;
container.clear();