使用allocator为多态对象分配内存

时间:2017-04-29 22:27:30

标签: c++ stl allocator

非常简单的问题 - 如何通过分配器为多态对象分配和释放内存?好的,分配内存不是一个大问题:

SomeAllocator::rebind<Child>::other allocator;
Parent*pointer=allocator.allocate(1);
new(pointer) Child;

要解除分配此内存,我应该致电SomeAllocator::rebind<Child>::other::deallocate ...或SomeAllocator::rebind<GrandChild>::other::deallocate?它是多态对象,我不知道他究竟是什么类型的。所以,我不知道我必须拨打什么分配器。我可以想象一些技巧。例如 - 通过std::allocator<char>().allocate(sizeof(ObjectType))std::allocator<char>().deallocate((char*)pointer,sizeof(ObjectType))分配和释放内存。但是这个伎俩抛弃了任何潜在的优化,例如&#34;这个分配器使用了Child对象池#34;另外,在多态对象中,我不知道这个对象的sizeof。所以,我必须在某处保存这个尺寸。分配实现后已经保存了它(当然,只有99%的情况下,allocate() - 只是重定向到malloc,lol)。它不认为这是非常好的做法。此外,我可以使用虚拟功能,如:

virtual void Child::destroy(){
    ~Child();
    SomeAllocator::rebind<Child>::other().deallocate(this,1);
}

但它也不是很好主意,因为我必须在所有派生类中复制此代码。

那么,为多态对象vis分配器分配和释放内存的最佳决策是什么? PS对不起,如果我的英语不好。

1 个答案:

答案 0 :(得分:1)

我会考虑使用概念/模型习语。

该概念定义了公共接口上可用的概念(服务),该模型描述了处理分配器转换和存储的实现。

e.g:

#include <memory>

struct I
{
    virtual ~I() = default;
};

struct A : I
{
    int x, y, z;
};

struct B : I
{
    int a, b, c, x, y, z;
};

template<class T> struct tag {};

struct IPtr
{
    struct concept
    {
        template<class T> void construct(void * addr)
        {
            ptr_ = new (addr) T ();
        }


        virtual void dealloc() = 0;

        void destroy() 
        { 
            ptr_->~I(); 
            dealloc();
        }

        void* mem_ = nullptr;
        I* ptr_ = nullptr;
    };

    template<class T, class Allocator>
    struct model : concept
    {
        model(Allocator alloc) 
        : alloc_(alloc) 
        {
            using A2 = typename Allocator::template rebind<T>::other;
            auto a2 = A2(alloc_);
            mem_ = a2.allocate(1);
            ptr_ = new (mem_) T ();
        }

        virtual void dealloc() override
        {
            using A2 = typename Allocator::template rebind<T>::other;
            auto a2 = A2(alloc_);
            a2.deallocate(reinterpret_cast<typename A2::pointer>(mem_), 1);
        }

        Allocator alloc_;
    };

    template<class T, class Allocator>
    IPtr(tag<T>, Allocator alloc)
    : impl_(new model<T, Allocator>(alloc))
    {

    }

    IPtr(IPtr&& r) 
    : impl_(r.impl_)
    {
        r.impl_ = nullptr;
    }

    ~IPtr()
    {
        if (impl_) {
            impl_->destroy();
            delete impl_;
        }
    }

private:
    concept* impl_;

};


int main()
{
    auto alloc = std::allocator<int>();
    auto a = IPtr(tag<A>(), alloc);
    auto b = IPtr(tag<B>(), alloc);

    a;
    b;
}