利用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));
}
};
然後,對於任何容器,只需使用上面自定義的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()進行優化