Let Base
and Derived
be classes with data members:
class Base {
public:
Base(int i):f(i) { }
virtual void print() { cout << "base " << f << endl; }
int f;
};
class Derived: public Base {
public:
Derived(int i):Base(0),g(i) { }
void print() { cout << "derived " << g << endl; }
int g;
};
Now create some instances of Base
and Derived
on the heap and store them in a boost::ptr_vector
:
int main(int argc, char *argv[])
{
boost::ptr_vector<Base> v;
v.push_back(new Derived(1));
v.push_back(new Base(2));
v.push_back(new Base(3));
v.push_back(new Derived(4));
print all the objects:
for (std::size_t i(0); i != v.size(); ++i)
v[i].print();
then reverse and print again:
std::reverse(v.begin(), v.end());
for (std::size_t i(0); i != v.size(); ++i)
v[i].print();
}
This program prints:
derived 1
base 2
base 3
derived 4
derived 1
base 3
base 2
derived 4
std::reverse()
on boost::ptr_vector
calls std::iter_swap()
which in turn calls std::swap
which swaps items by creating a temporary copy.
However, the temporary copy does slice the Derived objects. As you can see, the int g
of the Derived
objects 1 and 4 are not swapped, so the objects are broken after the swap.
This behavior puzzles me. Isn't boost::ptr_vector
a container to avoid exactly this kind of problem?
What I'd need here is a virtual copy constructor, which doesn't exist in C++.
How can I work around this? Do I need to implement a virtual swap function for Base
, so that virtual dispatching calls another swap member function of Derived
?
EDIT: Why copy objects in the first place? As the vector only stores pointers, reversing it should be a swap of the pointers, not the objects pointed to! Is there a function that does that?
One possible work around is to use
std::reverse(v.base().begin(), v.base().end());
instead. It reverses the pointers instead of the self-indirecting iterators.