c++stdswapboost-ptr-container

std::reverse on boost::ptr_vector slices objects?


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?


Solution

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