利用C++的new和delete操作符重载特性,可以对自定义的struct和class进行统一内存管理,再加上STL allocator的开放特性,便可以将STL容器对象的内存管理并入struct和class的内存管理,进而将这三者的内存管理统一。
首先实现自定义的内存管理算法框架,开放接口为allocate和deallocate,实现库为memmgr.dll
class memory_manager
{
public:
virtual void* allocate(size_t size) = 0;
virtual void deallocate(void* ptr, size_t size) = 0;
}
通过显示加载或隐式链接得到memmgr.dll导出的自定义内存管理框架接口指针
memory_manager* ptrmemmgr;
针对struct和class,建立公共基类,并调用导出的内存管理相关接口
class basic_object
{
public:
void* operator new(size_t size)
{
return (ptrmemmgr->allocate(size);
}
void operator delete(void* ptr, size_t size);
{
ptrmemmgr->deallocate(ptr, size);
}
};
自此,对于任意的自定义struct和class,都可以公共继承自basic_object,调用new和delete时便会调用basic_object::new和basic_object::delete接口,如下示例
class example : public basic_object
{
public:
// 这里省略成员函数和成员变量的声明和实现,就像没有继承自basic_object时一样
};
当对example进行new和delete操作时,编译器将产生调用basic_object::new和basic_object::delete的代码
至此,已将struct和class的内存管理统一了
对于STL,由于STL的所有容器都有一个allocator的模板参数,因此我们需要自定义allocator
template<typename T>
class newallocator : public std::allocator<T>
{
public:
template<typename O>
struct rebind
{
typedef newallocator<O> other;
}
template<typename O>
newallocator(newallocator<O> const&) throw()
{
}
template<typename O>
newallocator<T>& operator=(newallocator<O> const&) throw()
{
return (*this);
}
T* allocate(size_type count)
{
return (basic_object::operator new(count * sizeof(T));
}
void deallocate(T* ptr, size_type count)
{
basic_object::operator delete(ptr, count * sizeof(T));
}
};
template<typename T>
class newallocator : public std::allocator<T>
{
public:
template<typename O>
struct rebind
{
typedef newallocator<O> other;
}
template<typename O>
newallocator(newallocator<O> const&) throw()
{
}
template<typename O>
newallocator<T>& operator=(newallocator<O> const&) throw()
{
return (*this);
}
T* allocate(size_type count)
{
return (basic_object::operator new(count * sizeof(T));
}
void deallocate(T* ptr, size_type count)
{
basic_object::operator delete(ptr, count * sizeof(T));
}
};
然后,对于任何容器,只需使用上面自定义的newallocator即可,如
std::vector<int, newallocator<int>> vtexample;
std::map<int, int, std::less<int>, newallocator<std::pair<int const, int>>> mapexample;
至此,STL容器的内存管理也并入memory_manager里了,三者的内存管理达成统一。
注意:
(1)由于这里只重载了operator new和operator delete,因此只为struct和class的单个对象有效,对于数组仍会使用全局的::operator new[]和::operator dlete[]。当然也可以重载operator new[]和operator delete[]操作符,这样便将数组的内存管理也并入memory_manager里了。
(2)使用自定义的内存管理框架后,对于struct,由于有了成员函数,便不能使用声明时初始化数组的方式,如
struct stu stuexample = {0}; // 这种使用方式将导致编译错误,但可以使用memset(&stuexample, 0, sizeof(stu))
(3)可以为operator new(或者new[])加入更多的参数,如文件名和行数,进行debug下的内存泄漏检测
(4)重载operator delete[]时,应该使用operator delete[](void* ptr),否则使用operator delete[](void* ptr, size_t size)时传入的参数size只是一个对象的大小,而不是整个数组的大小
(5)如果自定义实现的内存管理框架中可以保证不产生异常,对于basic_object和newallocator可以使用throw()进行优化