#include <boost/ptr_container/ptr_vector.hpp>
#include <iostream>
using namespace std;
class Derived
{
public:
int i;
Derived() {cout<<"Constructed Derived"<<endl;}
Derived(int ii):i(ii) {cout<<"Constructed Derived"<<i<<endl;}
~Derived() {cout<<"* Destructed Derived"<<i<<endl;}
};
int main()
{
boost::ptr_vector<Derived> pv;
for(int i=0;i<10;++i) pv.push_back(new Derived(i));
boost::ptr_vector<Derived>::iterator it;
for (it=pv.begin(); it<pv.end();/*no iterator increment*/ )
pv.erase(it);
cout<<"Done erasing..."<<endl;
}
Notice that the second for loop does not increment the iterator, yet it iterates and erases all elements. My questions are:
开发者_运维技巧
- Is my technique of iteration and using the iterator correct?
- If iterator increment is not required in the for loop, then where does the increment happen?
- Is it better to use an iterator or will an ordinary integer suffice (ie: is there any value-add with using iterators)? (coz I can also erase the 5th element like pv.erase(pv.begin()+5);)
- Is there any way to assign a new object to a specific position (let's say the 5th position) of ptr_vector, directly? I'm looking for something like pv[5]=new Derived(5);. Any way of doing that?
A ptr_vector::iterator
increments just like a normal random access iterator. In your example, you are able to erase every element without actually incrementing because after you erase an element, every element after it is moved over in the array. So when you erase the 0th element, your iterator now points to the element which used to be the 1st element, but is now the 0th element, and so on. In other words, the iterator is staying in place while the whole vector is shifting over to the left.
This has nothing specifically to do with ptr_vector. Note the same behavior would occur with a plain std::vector
.
Also note that using an iterator after you erase the element it points to is dangerous. In your case it works, but it's better to take the return value of ptr_vector::erase
so you get a new iterator which is guaranteed to be valid.
for (it = pv.begin(); it != pv.end(); )
it = pv.erase(it);
As for your other questions:
If you only want to erase a specific element, then of course you should erase it directly using pv.erase(pv.begin() + N)
. To assign a new value to a specific element in the pointer vector, simply say pv[N] = Derived(whatever)
. You don't need to use new
when reassigning a value. The pointer vector will invoke the assignment operator of the object at the index you assign the new value to.
Is my technique of iteration and using the iterator correct?
No, erasing from a container generally invalidates the iterator to the erased item. If it works, this is just a side-effect of the implementation details.
The correct way would be to use the return value of the erase method:
it = pv.erase(it);
However, for emptying the container, you can use the clear member function.
If iterator increment is not required in the for loop, then where does the increment happen?
It doesn't happen, because you'll always be erasing the first item in the container (by chance, might not work out with other containers).
Is it better to use an iterator or will an ordinary integer suffice (ie: is there any value-add with using iterators)? (coz I can also erase the 5th element like
pv.erase(pv.begin()+5);
)
In a random-access container you can do that, otherwise not (such as a list).
Is there any way to assign a new object to a specific position (let's say the 5th position) of ptr_vector, directly? I'm looking for something like
pv[5]=new Derived(5);
. Any way of doing that?
According to the boost reference:
pv.replace(5, new Derived(5));
This returns the existing pointer in a smart pointer, so it will be automatically deallocated. (It's curious that this takes an index, not an iterator...).
Or:
pv[5] = Derived(5);
but this will just modify the stored object, not change the pointer.
精彩评论