2014-01-30 71 views
0

我最近一直在閱讀有關自定義的內存分配器爲C++和碰到的intressting概念在那裏,而不是使用指針「手柄」使用哪些是有效的指針的指針,這使得分配到重新排列其內存以避免碎片,同時避免使所有指向已分配內存的指針無效的問題。C++ - 從客戶端代碼隱藏模板參數

然而,不同的分配器不妨以不同的方式使用手柄,例如池分配器就沒有必要重新安排它的內存,在其他分配器會。那些需要重新排列內存的應用程序可能需要將句柄當作指向指針的指針,指向指針數組的索引等,而不重新排列其內存的分配器會將句柄視爲簡單指針。理想情況下,每個分配器將能夠使用不同類型的句柄,以便它可以實現最佳性能,具有虛擬方法的基本句柄類會產生很多開銷,因爲每次需要訪問任何函數/成員時都會使用句柄一個動態分配的類。

我的解決方案是使用模板偏特使手柄類型在編譯時制定出來,消除虛函數的運行時間開銷,讓編譯器做其他的優化(如:內聯)

///////////////////////////////////////////////// 
/// \brief The basic handle class, acts as simple pointer 
/// Single layer of indirection 
///////////////////////////////////////////////// 
template <typename T> 
class Handle{ 
public: 
    T* operator->(){return obj;} 
    //other methods... 
private: 
    T* obj; 
}; 

///////////////////////////////////////////////// 
/// \brief Pointer specialization of the handle class, acts as a pointer to pointer 
/// allowing allocators to rearrange their data 
///////////////////////////////////////////////// 
template <typename T> 
class Handle<T *>{ 
public: 
    T* operator->(){return *obj;}; 
    //other methods... 
private: 
    T** obj; 
}; 

這很好地工作,並允許分配器返回他們需要的任何類型的句柄,但是這意味着任何需要把句柄作爲參數的函數都需要被重載以接受這兩種類型的特化,也就是一個把句柄作爲成員的類將需要模板化,以確定它是否具有正常的句柄,指向指針句柄的指針或其他類型。

這個問題只會隨着增加更多的句柄類型更壞的或函數有不止一個手柄和手柄類型的所有組合必須有一個過載。

要麼我需要能夠使所有指向「TypeA」實例的句柄的類型爲Handle<TypeA>,然後使用不同的方法來模板專門化,以提供不同的功能或以某種方式隱藏任何代碼中的模板參數使用手柄。這怎麼可能實現? (這種隱藏模板參數的方法在其他情況下也是有用的,例如policy based logging system,其中一個類可能希望保存對任何類型的記錄器的引用而本身不被模板化。顯然,在虛擬記錄的情況下繼承可以作爲速度的主要因素將是I/O,而不是函數調用的開銷)

+0

C++分配器模型從未完成,現在永久無用作爲內存模型。它只是用於不同的內存分配策略。但處理事情並不實際工作。 :(對不起。 –

+0

http://en.wikipedia.org/wiki/Allocator_(C%2B%2B)「......原本打算完全封裝內存模型的分配器,標準委員會意識到這種方法會導致不可接受爲了解決這個問題,在分配器的需求中增加了額外的措辭,特別是容器實現可以假設分配器的指針類型定義和相關的整型類型與默認分配器提供的類型定義是等價的,並且......有效地矛盾分配器的原始設計目標......「 –

+0

處理您的問題的常用方法是在參數類型上創建函數模板,以便人們可以通過Handle '或'T *'。 –

回答

3

我已經實現,允許正是你描述的存儲系統,但也想不出辦法有獨特的手柄沒有虛擬功能的類型。模板參數是類型的一部分。

最後我做了一個單一的句柄類型,並使用指針的最低有效位來存儲它是直接指針還是間接指針。在取消引用之前,我會檢查該位,如果沒有設置,我只是簡單地返回指針,否則我將取消該位並向內存系統詢問實際指針。

的方案做了工作,但我最終刪除從我的記憶系統間接內存手柄的支持,我發現開銷可能會非常高,因爲它是在我的代碼方方面面所以侵入。基本上幾乎在任何地方都會使用指針,我不得不使用句柄。它還要求在使用其他線程之前鎖定內存,以便在使用時不會進行碎片整理。最後,它要求我編寫完全自定義的容器以獲得可接受的性能。例如,我不希望在循環中的每個向量訪問上存在雙重間接。