如何使用自定义内存管理器定义RAII缓冲区类



下面的问题可能是关于设计模式的一般问题,但由于我缺乏知识,我做不到。

我正在尝试使用具有open_manager/close_manager/allocate/deallocate等接口的给定内存管理器类(MemoryManager(来实现RAII风格的缓冲区类(Buffer(。Buffer看起来像:

class Buffer {
public:
explicit Buffer(std::size_t sz) { /* Allocation */ }
~Buffer() { /* Deallocation */ }
};

但作为一个条件,MemoryManager类需要实例化,这意味着Buffer需要能够在析构函数中使用特定的管理器实例。

~Buffer() { manager.dealloc(/* ... */); }

有几种选择:

  • const MemoryManager*作为Buffer成员变量,如:
    class Buffer {
    public:
    Buffer(std::size_t sz, const MemoryManager* manager) : manager_(manager) { /*...*/ }
    ~Buffer() { manager_->dealloc(/*...*/); }
    private:
    const MemoryMenager* manager_{nullptr};
    };
    
  • const MemoryManager&作为Buffer成员变量
  • 作为全局变量的管理者

哪些选项是最好的?或者有什么更好的方法可以做到这一点?

谢谢。

EDIA:关于MemoryManager

MemoryManager应该封装较低级别的有状态的东西,并且应该有一个类的实例。

class MemoryManager {
public:
/* Interfaces might be like this */ 
MemoryManager(); // open lower level mem manager
~MemoryManager(); // close lower level mem manager
void Allocate();
void Deallocate();
/* etc. */
private:
handle handle_; /* low level object */
};

注释中的OP指定:

MemoryManager应该是一个单一实例

如果实例类型不需要从未绑定的集合中进行运行时选择,那么可以选择模板。标准库正在大量使用它。下面是一个非常简单的例子,向您展示了这个想法。有关异常安全的更多信息,请参阅此链接http://www.gotw.ca/gotw/008.htm在这里https://www.stroustrup.com/except.pdf

#include <cstddef>
struct MyAllocator
{
static char* allocate( std::size_t n ) { return new char[n]; }
static void deallocate( char* p) { delete[] p; }
};
template<typename Allocator>
class BufferImpl {
char* buffer;
public:
explicit BufferImpl(std::size_t sz) : buffer(Allocator::allocate(sz)) { }
~BufferImpl() { Allocator::deallocate(buffer); }
};
typedef BufferImpl<MyAllocator> Buffer;
int main() {
Buffer b(100);
return 0;
}

Allocator是在编译时注入的,如果你有多个Allocator类型,你可以创建多个typedef并提供一个工厂方法来构造对象。

在标准库中,分配器也是一个模板类,为了简单起见,我只使用了char*。

当分配器类是一个模板时,分配内存和构造对象的方式将对类型T施加约束。标准库通常要求对象是可复制可构造的,上面的天真实现要求对象是默认可构造的。看见https://en.cppreference.com/w/cpp/memory/allocator以供参考。

最新更新