前面的系列咱們講了自定義new和delete操做,其中針對deleteArray的問題還有須要優化的地方。咱們此次就針對POD類型進行一次優化。html
下面的代碼是針對POD類型的模板函數實現,分別爲NewArrayPOD和DeleteArrayPOD:wordpress
template <typename T, class ARENA> T* NewArrayPOD(ARENA& arena, size_t N, const char* file, int line) { return static_cast(arena.Allocate(sizeof(T)*N, file, line)); } template <typename T, class ARENA> void DeleteArrayPOD(T* ptr, ARENA& arena) { arena.Free(ptr); }
從上面能夠看出,針對POD類型,咱們不須要調用析構函數,只須要將內存釋放便可,因此其區別於非POD類型。可是若是實現了POD和非POD兩個版本的函數,該如何讓咱們的宏根據類型本身調用合適的函數呢?函數
咱們採用的方式是放棄NewArrayPOD和DeleteArrayPOD這種另外實現一個函數的方式,而是重載NewArray和DeleteArray函數,使宏根據參數來正確調用對應的函數。咱們首先要實現的是一個traits-class,它用來判斷一個類型是否是POD類型。這能夠經過定義一個基礎模板類和一些特化版原本實現,代碼以下:優化
template <typename T> struct IsPOD { static const bool Value = false; }; template <> struct IsPOD<char> { static const bool Value = true; }; template <> struct IsPOD<int> { static const bool Value = true; }; // etc.
對於任何一個給定的類型T,咱們能夠經過編譯期常量IsPOD<T>::value來肯定T是否爲一個POD類型。固然了,若是使用了C++11及之後的標準,標準庫中就實現了std::is_pod。ui
兩個重載版本的函數實現以下:spa
template <typename T, class ARENA> T* NewArray(ARENA& arena, size_t N, const char* file, int line, NonPODType) { // implementation for non-POD types } template <typename T, class ARENA> T* NewArray(ARENA& arena, size_t N, const char* file, int line, PODType) { // implementation for POD types } template <typename T, class ARENA> void DeleteArray(T* ptr, ARENA& arena, NonPODType) { // implementation for non-POD types } template <typename T, class ARENA> void DeleteArray(T* ptr, ARENA& arena, PODType) { // implementation for POD types }
固然了,看到上面的代碼後,你可能會問,C++的重載是根據類型來的,又不是根據值,咱們不能只經過一個true和一個false來重載函數。因此爲了讓上面的代碼可以正確工做,咱們須要再實現一個模板黑魔法稱爲type-based dispatching。code
template <bool I> struct IntToType { }; typedef IntToType<false> NonPODType; typedef IntToType<true> PODType;
這樣,咱們就能夠將上一節中的宏定義修改成:htm
// old version #define ME_NEW_ARRAY(type, arena) NewArray<TypeAndCount<type>::Type>(arena, TypeAndCount<type>::Count, __FILE__, __LINE__) // new version #define ME_NEW_ARRAY(type, arena) NewArray<TypeAndCount<type>::Type>(arena, TypeAndCount<type>::Count, __FILE__, __LINE__, IntToType<IsPOD<TypeAndCount<type>::Type>::Value>())
有點小長,可是若是理解了背後的技巧和原理,實現起來其實並不複雜。可是咱們還有最後一個問題,就是在宏定義#define OM_DELETE_ARRAY(object, arena) DeleteArray(object, arena)中不能直接使用Is_POD<T>方法,由於obejct自己是一個值,不是一個一個類型,咱們又不想顯式的再用一個參數來制定類型,由於編譯器已經知道了類型,因此咱們要作的就是讓編譯器本身推到出類型再調用DeleteArray函數,因此咱們只需將DeleteArray函數封裝在一個模板函數中,就能夠實現這一點,代碼以下:blog
template <typename T, class ARENA> void DeleteArray(T* ptr, ARENA& arena) { DeleteArray(ptr, arena, IntToType<IsPOD<T>::Value>()); }
至此爲止,咱們對POD和非POD類型的優化工做已經結束,如今咱們能夠高效的使用自定義的OM_NEW_ARRAY和OM_DELETE_ARRAY了。內存
參考link:
https://stoyannk.wordpress.com/2018/01/10/generic-memory-allocator-for-c-part-3/
https://bitsquid.blogspot.com/2010/09/custom-memory-allocation-in-c.html
https://blog.molecular-matters.com/