下面的问题可能是关于设计模式的一般问题,但由于我缺乏知识,我做不到。
我正在尝试使用具有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以供参考。