views:

480

answers:

4

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?

+10  A: 
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().

sbi
Excellent advice, especially bullet #2. But stefaanv is right, constructor-style casts won't work for pointer types -- do as he suggests instead.
j_random_hacker
I do agree with the comments and I like the new loop
stefaanv
Even better -- get rid of `Shutdown()` altogether and put the functionality in the destructor (which must become `virtual` since you will be deleting a derived class via a base class pointer). Use a `vector<boost::smart_ptr<BaseClass> >` instead, and then you won't need to remember to do *anything!*
j_random_hacker
Thanks, I have added another pair of parentheses to the cast. It looks really ugly now (good, it's smelly anyway), but it's still hard to grep for (bad). I should use a checked `dynamic_cast` instead, but then I'd have to re-phrase my notes... I feel dirty, though. `:-)`
sbi
It's just an example and if you remove the '_', it could even compile ;)
stefaanv
@stefaanv: Thanks, I have no idea how that crept in.
sbi
+1  A: 

The constructor casting doesn't work for pointers. Use static_cast if you're sure or dynamic_cast and check.

stefaanv
A: 

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.

davidnr
Have you looked at what `iter` is initialized with and what it is compared to? And which one would you choose so that the `myVector.pop_back()` doesn't wreak havoc with the iterator? And if there are _several_ derived classes having a `ShutDownX()` function, it should _very_ likely be a virtual function declared in the base class.
sbi
I was just making the minimal changes to his design. Of course it should be derived, and the whole loop could be written in two lines.
davidnr
+2  A: 

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++.

markh44
I guess `rbegin()` vs. `end()` might give trouble, too. Using `clear()` is a very good idea, though.
sbi
@sbi meh, how did that get in there? I'm sure I copy and pasted that code...
markh44
@markh44: That's the problem. It was one of the problems with the original code.
sbi
@sbi that's ok then I thought I'd finally gone mad.
markh44