Разработать класс, который может быть создан только конкретным классом (если возможно, make_unique) - PullRequest
0 голосов
/ 05 ноября 2018

Я реализую простой пул памяти, и в моей реализации есть два класса.

FixedMemoryPool<T> и MemoryBlock<T>

FixedMemoryPool предоставляет пользователям такие интерфейсы, как newElement, и управляет памятью через 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;
};

Спасибо за эту ссылку . Я знаю, как включить make_unique с частным ctor. Тем не менее, я хочу знать, есть ли лучший способ выполнить мое желание.

Кроме того, мое использование для operator new и operator delete верно?

1 Ответ

0 голосов
/ 05 ноября 2018

Немного не по теме, но нет никаких оснований для MemoryBlock знать о типе T.

В вашей реализации, когда вы создаете MemoryBlock, а затем уничтожаете его, он в конечном итоге вызывает деструкторы объектов, которые никогда не создавались, что является неопределенным поведением.

MemoryBlock должен знать только размер объекта и количество объектов в блоке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...