设计一个只能由特定类实例化的类(如果可能,可以通过make_unique实例化)

时间:2018-11-05 10:13:15

标签: c++ c++11 templates

我正在实现一个朴素的内存池,我的实现中有两个类。

FixedMemoryPool<T>MemoryBlock<T>

FixedMemoryPoolnewElement之类的用户提供接口,并通过MemoryBlock管理内存。

很明显,没有用户可以访问MemoryBlock,它的生命周期完全由FixedMemoryPool管理。对于每个MemoryBlock<T>,只能由FixedMemoryPool<T>创建。

这是我的实现方式。

template
<typename T>
class FixedMemoryPool;

template<typename T>
class MemoryBlock
{
    friend class FixedMemoryPool<T>;
    using blockPtr = unique_ptr<MemoryBlock<T>>;
    struct _ConstructorTag { explicit _ConstructorTag() = default; };
public:
    MemoryBlock(size_t blockSize, _ConstructorTag)
        :data(reinterpret_cast<T*>(operator new(sizeof(T) * blockSize))), allocatedCounter(0), next(nullptr)
    {
    }

    ~MemoryBlock()
    {
        for (size_t i = 0; i != allocatedCounter; i++) {
            (data + i) -> ~T();
        }
        operator delete(data);
    }
private:
    T* data;
    size_t allocatedCounter;

    blockPtr next;

    template
    <typename... Args>
    T* construct(Args&&... args)
    {
        return new (data + (allocatedCounter++)) T(std::forward<Args>(args)...);
    }

    MemoryBlock(const MemoryBlock&) = delete;
    MemoryBlock& operator=(const MemoryBlock&) = delete;
};

template
<typename T>
class FixedMemoryPool 
{
public:
    using valueType = T;

    FixedMemoryPool(size_t blockSize = 64)
        :blockSize(blockSize), head(make_unique<MemoryBlock<T>>(blockSize, MemoryBlock<T>::_ConstructorTag{}))
    {
    }

    FixedMemoryPool(const FixedMemoryPool&) = delete;
    FixedMemoryPool& operator=(const FixedMemoryPool&) = delete;

    FixedMemoryPool(FixedMemoryPool&& pool) = delete;
    FixedMemoryPool& operator=(FixedMemoryPool&&) = delete;

    template
    <typename... Args>
    T* newElement(Args&&... args)
    {
        //...
    }

    ~FixedMemoryPool() = default;
private:
    void expand()
    {
        // ...
    }

    size_t blockSize;

    unique_ptr<MemoryBlock<T>> head;
};

感谢link。我知道如何使用私有ctor启用make_unique。 但是,我想知道是否有更好的方法可以满足我的愿望。

我对operator newoperator delete的用法正确吗?

1 个答案:

答案 0 :(得分:1)

有点题外话,但MemoryBlock没有理由知道类型T

在实现中,创建MemoryBlock然后销毁它时,它最终会调用从未构造的对象的析构函数,这是未定义的行为。

MemoryBlock仅应了解块中的对象大小和对象数。