2

I need to have a std::vector of boost::ptr_vectors. To make their management easier, I enclosed the boost::ptr_vector in a class (Zoo) and made a std::vector of it (allZoos). Look at a minimal code for reproducing this:

#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/utility.hpp>

class Animal
{
public:
    virtual char type() = 0;
};

class Cat : public Animal
{
public:
    char type() { return 1; }
};

class Zoo
{
public:
    boost::ptr_vector<Animal> animals;
};


int main()
{
    std::vector<Zoo> allZoos;

    Zoo ourCityZoo;
    ourCityZoo.animals.push_back(new Cat());

    //Uncommenting any of the lines below causes error:
    //allZoos.push_back(ourCityZoo);
    //allZoos.clear();

    return 0;
}

Declaring allZoos is okay, but calling any of its member functions causes the compiler error: (The full error log was so long, not posted)

C2259: 'Animal' : cannot instantiate abstract class c:\boost_1_49_0\boost\ptr_container\clone_allocator.hpp 34  1

This had nothing to do with boost's noncopyable utility class and custom new_clone functions and I tried them with no luck. How can that be solved?

(I'm using VS2010)

Hossein
  • 4,097
  • 2
  • 24
  • 46
  • The easiest solution would probably be to ditch `ptr_vector` and use a `std::vector>` instead. – Xeo Mar 10 '12 at 08:45
  • @Xeo: Yes, right now I'm using a temporary workaround like that; but afterall `ptr_vector` was created to provide a replacement for such templates and "has to" work! I'm also curious to know why `std::vector>` simply works, but the code in the question doesn't. – Hossein Mar 10 '12 at 08:52

1 Answers1

9

Actually, reading into where the error appears would've helped. It's stated clear and plainly in the Boost source:

template< class T >
inline T* new_clone( const T& r )
{
    //
    // @remark: if you get a compile-error here,
    //          it is most likely because you did not
    //          define new_clone( const T& ) in the namespace
    //          of T.
    //
    T* res = new T( r );
    BOOST_ASSERT( typeid(r) == typeid(*res) &&
                  "Default new_clone() sliced object!" );
    return res;
}

If you don't specify a way to clone the type, it will try to do so by simply copying it, which isn't possible with abstract classes. Add an appropriate clone method to the abstract_class and a new_clone function in its namespace and you'll be fine.

Here's a fixed version of your code.

Xeo
  • 129,499
  • 52
  • 291
  • 397
  • Thanks! So I didn't know how to use the clones. I thought `ptr_vector` doesn't need to clone its objects; but after reading it seems many of its function rely on cloning the objects it contains. – Hossein Mar 10 '12 at 10:03