Hey, In C++, I have a vector of type:
vector<BaseClass*> myVector;
In which, I insert (push_back) pointers of derived classes into it.
Now, I want to pop back its elements so I do this:
vector<ADlgcDev*>::iterator iter;
for (iter = myVector.rbegin(); iter != myVector.rend(); iter++)
{
// but before I pop it, I need to shutdown it down
// so I cast this
// but this way, I'm unable to call the function
(DerivedClass*(*iter))->Shutdown();
myVector.pop_back();
}
but as mention in the comments before I pop it, I need to call its Shutdown() method and the cast is not working properly too. Any resolutions? or is impossible?
while (!myVector.empty())
{
((DerivedClass*)(myVector.back()))->Shutdown();
myVector.pop_back();
}
Notes:
You should probably use dynamic_cast instead of the hard cast. (If it's sure that there are only DerivedClass objects in the vector, why isn't it std::vector<DerivedClass>?)
You should probably not have to cast at all, since Shutdown() should be declared in the base class.
You should probably delete the objects, too, before you pop them off the vector. (But that might not be so.)
You should probably use a smart pointer which calls Shutdown() (and delete, probably).
Edit: Using std::vector<T>::clear(), as shown by markh44 is probably better than the pop_back().
Could you make Shutdown a virtual function in BaseClass? Then you wouldn't need a cast.
Also you'll probably have trouble removing items from a vector while iterating. I'd do it like this:
vector<BaseClass*>::iterator iter;
for (iter = myVector.rbegin(); iter != myVector.rend(); iter++)
{
(*iter)->Shutdown();
}
myVector.clear();
Edit: and another thing, ++iter is generally preferred over iter++.
The constructor casting doesn't work for pointers. Use static_cast if you're sure or dynamic_cast and check.
If Shutdown() is a virtual method of the Base class i.e. BaseClass::ShutDown() you should directly call iter->ShutDown();
Otherwise if the method isn't virtual you should use dynamic_cast.
vector<ADlgcDev*>::iterator iter;
for (iter = myVector.rbegin(); iter != myVector.end(); iter++)
{
DerivedClassA* a = dynamic_cast<DerivedClassA*>( *iter ) ;
if ( a ) a->ShutDownA();
else
{
DerivedClassB* b = dynamic_cast<DerivedClassB*>(*iter);
if ( b ) b->ShutDownB();
// ... repeat for every class in hierarchy that might be in the vector.
}
myVector.pop_back();
}
Anyway you're probably leaking memory, unless ShutDown() deletes the object from itself (which is generally a bad idea ) or you're keeping duplicated pointers and deleting them elsewhere, which is another risky idea.
Related
Can anyone help me with why this code give me a segmentation fault on the inner loop?
I am trying to iterate on a list of vectors of some class block.
class chain
{
list<vector<Block*>* >* _blockChain;
}
Chain* someChain = new Chain();
for(list<vector<Block*>*>::iterator listIter = someChain->getChain()->end() ;
listIter != someChain->getChain()->begin(); listIter--)
{
for(vector<Block*>::iterator it = (*listIter)->begin();
it != (*listIter)->end() ; it++)
{
//do something
}
}
If you want to iterate through the list in reverse, use a reverse_iterator:
for(list<vector<Block*>*>::reverse_iterator listIter = someChain->getChain()->rbegin();
listIter != someChain->getChain()->rend(); ++listIter)
With a recent compiler you can condense that down a bit:
for (auto listIter = someChain->getChain()->rbegin();
listIter != someChain->getChain()->rend(); ++listIter)
That said, I agree with #Mike Seymour: you are using way too many pointers. For one really obvious example, there's almost never a reason to use a pointer to a vector (because a vector is itself little more than a wrapper around a pointer to data, with a little extra data for book-keeping about how much data is in the vector).
The first time you try to access listIter it is pointing to end() which is not to be dereferenced. In the inner loop you dereference listIter and try to use it.
From http://en.cppreference.com/w/cpp/container/vector/end
This element acts as a placeholder; attempting to access it results in undefined behavior.
I think you face a crash in List::end() and List::begin(). It's because you has not initialized your List anywhere in your code (at least I don't see in your given code). you need:
class Chain{
Chain()
{
_blockChain = new list<vector<int*>* >;
// initializing Vector and so on
}
};
Although this is not all of your problems.
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();
I have a map declared as
std::map<std::string, Texture*> textureMap;
which I use for pairing the path to a texture file to the actual texture so I can reference the texture by the path without loading the same texture a bunch of times for individual sprites. What I don't know how to do is properly destroy the textures in the destructor for the ResourceManager class (where the map is).
I thought about using a loop with an iterator like this:
ResourceManager::~ResourceManager()
{
for(std::map<std::string, Texture*>::iterator itr = textureMap.begin(); itr != textureMap.end(); itr++)
{
delete (*itr);
}
}
But that doesn't work, it says delete expected a pointer. It's pretty late so I'm probably just missing something obvious, but I wanted to get this working before bed. So am I close or am I totally in the wrong direction with this?
As far as your sample code goes, you need to do this inside the loop:
delete itr->second;
The map has two elements and you need to delete the second. In your case, itr->first is a std::string and itr->second is a Texture*.
If you need to delete a particular entry, you could do something like this:
std::map<std::string, Texture*>::iterator itr = textureMap.find("some/path.png");
if (itr != textureMap.end())
{
// found it - delete it
delete itr->second;
textureMap.erase(itr);
}
You have to make sure that the entry exists in the map otherwise you may get an exception when trying to delete the texture pointer.
An alternative might be to use std::shared_ptr instead of a raw pointer, then you could use a simpler syntax for removing an item from the map and let the std::shared_ptr handle the deletion of the underlying object when appropriate. That way, you can use erase() with a key argument, like so:
// map using shared_ptr
std::map<std::string, std::shared_ptr<Texture>> textureMap;
// ... delete an entry ...
textureMap.erase("some/path.png");
That will do two things:
Remove the entry from the map, if it exists
If there are no other references to the Texture*, the object will be deleted
In order to use std::shared_ptr you'll either need a recent C++11 compiler, or Boost.
The answer didn't fully address the looping issue. At least Coverty (TM) doesn't allow erasing the iterator within the loop and still use it to continue looping. Anyway, after deleting the memory, calling clear() on the map should do the rest:
ResourceManager::~ResourceManager()
{
for(std::map<std::string, Texture*>::iterator itr = textureMap.begin(); itr != textureMap.end(); itr++)
{
delete (itr->second);
}
textureMap.clear();
}
You're not using the right tool for the job.
Pointers should not "own" data.
Use boost::ptr_map<std::string, Texture> instead.
How do I call a method of an object which is stored within a vector? The following code fails...
ClassA* class_derived_a = new ClassDerivedA;
ClassA* class_another_a = new ClassAnotherDerivedA;
vector<ClassA*> test_vector;
test_vector.push_back(class_derived_a);
test_vector.push_back(class_another_a);
for (vector<ClassA*>::iterator it = test_vector.begin(); it != test_vector.end(); it++)
it->printOutput();
The code retrieves the following error:
test3.cpp:47: error: request for
member ‘printOutput’ in ‘*
it.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator-> with _Iterator = ClassA**, _Container = std::vector >’, which
is of non-class type ‘ClassA*’
The problem seems to be it->printOutput(); but at the moment I don't know how to call the method properly, does anyone know?
regards mikey
The things in the vector are pointers. You need:
(*it)->printOutput();
which dereferences the iterator to get the pointer from the vector, then uses -> on the pointer to call the function. The syntax you show in your question would work if the vector contained objects rather than pointers, in which case the iterator acts like a pointer to one of those objects.
There is a Boost.PointerContainer library which could help you tremendously here.
First: it takes care of memory management, so you won't forget the release the memory pointed to.
Second: it provides a "dereferenced" interface so that you can use the iterators without the ugly patching (*it)->.
#include <boost/ptr_container/ptr_vector.hpp>
int main(int argc, char* argv[])
{
boost::ptr_vector<ClassA> vec;
vec.push_back(new DerivedA());
for (boost::ptr_vector<ClassA>::const_iterator it = vec.begin(), end = vec.end();
it != end; ++it)
it->printOutput();
}
From a Dependency Injection point of view, you might be willing to have printOutput takes a std::ostream& parameter so that you can direct it to whatever stream you want (it could perfectly default to std::cout)
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();