if we can support more function(in fact, more is safety) and don't need to pay cash, why not to add a virtual destructor?
Most of the solutions listed assume you defined a virtual destructor for Base, which explains again why it is so important to make all of your polymorphic classes' destructors virtual. If you fail to do this, deleteing a pointer to a base class that actually points to an object of a derived class engenders undefined behavior. The allocator discussed herein will assert in debug mode and crash your program in NDEBUG mode. Anybody would agree that this behavior fits comfortably into the realm of "undefined."
To protect you from having to remember all this (and from wasting nights debugging if you don't), SmallObject defines a virtual destructor. Any class that you derive from SmallObject will inherit its virtual destructor. This brings us to the implementation of SmallObject.
using your code, writing Test* p = new Test; the overhead of vptr is not in memory that operator new allcoated. it is in the type information of p. why? take account of below original text:
typedef Singleton<SmallObjAllocator> MyAlloc;
void* SmallObject::operator new(std::size_t size)
void SmallObject::operator delete(void* p, std::size_t size)
and test again? this way maybe better