C++ Memory System Part3 : 優化

前面的系列咱們講了自定義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/

相關文章
相關標籤/搜索