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?
Boost's ptr_vector
class contains member functions whose job is manipulate the underlying pointers. But the public interface largely hides the fact that the vector internally stores pointers. The idea is to produce something that behaves as if it contained the objects directly but internally stores pointers to avoid slicing when you put an object into the container. But if you copy an object out of the container into an object of the base type, then it will slice. So you must not call such functions on ptr_vector
s.
This means, unfortunately, that before you apply any algorithm to a ptr_vector
, you need to understand exactly what it does.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With