// http://stackoverflow.com/questions/37771121/stored-by-value-pool-that-support-polymorphism-how-to-use-smart-pointer
#include <unordered_map>
#include <iostream>
template<class T> struct Handle;
struct PoolBase
{
virtual void destroy(int index) = 0;
virtual void* get(int index) = 0;
virtual bool isAlive(int index) const = 0;
};
template<class T>
struct Pool : public PoolBase
{
int nextIndex;
typedef std::unordered_map<int, T> Map;
Map objects;
Pool() : nextIndex(0) {}
Handle<T> create()
{
int index = nextIndex++;
objects[index] = T();
return Handle<T>(this, index);
}
void destroy(int index) override
{
objects.erase(index);
}
void* get(int index) override
{
typename Map::iterator it = objects.find(index);
return it == objects.end() ? nullptr : &it->second;
}
bool isAlive(int index) const override
{
typename Map::const_iterator it = objects.find(index);
return it != objects.end();
}
};
template<class T>
struct Handle
{
PoolBase* pool_;
int pool_index_;
Handle() : pool_(nullptr), pool_index_(0) {}
Handle(PoolBase* pool, int index) : pool_(pool), pool_index_(index) {}
// Conversion Constructor
template<class D>
Handle(const Handle<D>& orig)
{
T* Cannot_cast_Handle = (D*)nullptr;
(void)Cannot_cast_Handle;
pool_ = orig.pool_;
pool_index_ = orig.pool_index_;
}
explicit operator bool() const
{
return pool_->isAlive(pool_index_);
}
T* operator->()
{
return static_cast<T*>( pool_->get(pool_index_) );
}
void destroy()
{
pool_->destroy(pool_index_);
}
};
template<class D, class S>
Handle<D> static_handle_cast(const Handle<S>& src)
{
return Handle<D>(src.pool_, src.pool_index_);
}
struct Base
{
virtual void print() { std::cout << "Base::print" << std::endl; }
};
struct Derived : public Base
{
void print() override { std::cout << "Derived::print" << std::endl; }
};
int main()
{
Pool<Derived> pool;
Handle<Derived> d = pool.create();
Handle<Base> b1 = d;
Handle<Base> b2 = pool.create();
if(b1)
b1->print();
if(b2)
b2->print();
b2 = d;
b1.destroy();
if(b1)
b1->print();
else
std::cout << "b1 is gone" << std::endl;
if(b2)
b2->print();
else
std::cout << "b2 is gone" << std::endl;
//Handle<Derived> d2 = b2; // Compile error - which is expected
Handle<Derived> d2 = static_handle_cast<Derived>(b2);
if(d2)
d2->print();
}