程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 基於策略模式的定制new和delete

基於策略模式的定制new和delete

編輯:C++入門知識

背景
   在面向對象類的設計中,有時為了強化效能,特別是當構造大量小對象時,為了改善內存碎片,就需要自己實現對象的內存管理,以替換系統缺省的分配和釋放行為,即全局的new和delete。按照c++標准,在定制類專屬的new和delete時,為了減免客戶代碼使用時的麻煩和問題,需要考慮同時定制簡單(normal new)、定位(placement new)和無異常(nothrow new)三種new情形,以及與之配對的三種delete情形,另外還有對應的數組new[]和delete[]各三種情形。在接口設計上,每種情形都是operator new和operator delete的重載版本;在內存管理上,具體的對象空間分配和釋放是靈活的,因此這一部分可實現為策略模式,通過改變替換不同的內存管理策略,即可輕易獲得不同的內存分配和釋放行為,而類的代碼則無須改變。為了方便定制類的new和delete,可以從一個接口基類模板繼承而自動獲得這種特性。這個基類模板實現了單個對象的new、delete和對象數組的new、delete,而模板參數正是內存管理策略類,它的設計約束如下:
   1)必須存在static成員方法malloc和free,其參數和返回值與C庫的malloc和free一致。
   2)malloc只分配空間,若分配成功則不必初始化,否則失敗返回NULL,不能拋出異常,因為normal new的語義為對於分配失敗則拋出std::bad_alloc異常,而nothrow new則返回NULL,如此兩種方式兼備,有利於客戶代碼的按需靈活檢測;free只釋放或歸還空間。
   3)malloc和free的內部實現是靈活的,由應用開發者定制。

組件
   這裡實現了new_delete_policy_base和object_pool_impl兩個基礎組件,代碼如下,前者是支持內存管理策略的定制new和delete接口基類模板,從該類繼承的子類其對象的構造和析構就被定制了;後者是支持內存管理策略的非侵入式對象池類模板,可直接用於構造某類的對象,包括內建的基本數據類型,而該類不必從new_delete_policy_base繼承。
 1template<class Alloc>
 2class new_delete_policy_base
 3{
 4public:
 5    static void* operator new(size_t size) throw (std::bad_alloc)
 6    { 
 7        void* ptr = Alloc::malloc(size);
 8        if(NULL==ptr) {
 9            throw std::bad_alloc();
10        }
11        return ptr;
12    }
13
14    static void* operator new(size_t size,void* ptr) throw()
15    { return ptr; }
16
17    static void* operator new(size_t size,const std::nothrow_t&) throw()
18    { return Alloc::malloc(size); }
19
20    static void operator delete(void* ptr) throw()
21    {  Alloc::free(ptr); }
22
23    static void operator delete(void* ptr, const std::nothrow_t&) throw()
24    {  Alloc::free(ptr); }
25
26    static void operator delete(void*, void*) throw()
27    { }
28
29    static void* operator new[](size_t size) throw(std::bad_alloc)
30    { return operator new (size); }
31   
32    static void* operator new[](size_t size,void* ptr) throw()
33    { return ptr; }
34
35    static void* operator new[](size_t size, const std::nothrow_t&) throw()
36    { return operator new (size, std::nothrow); }
37
38    static void operator delete[](void* ptr) throw()
39    {  operator delete (ptr); }
40
41    static void operator delete[](void* ptr, const std::nothrow_t&) throw()
42    { operator delete (ptr); }
43
44    static void operator delete[](void*, void*) throw()
45    { }
46};
47
48template<class Alloc>
49class object_pool_impl
50{
51public:
52    template<typename T>
53    static T* construct()
54    {
55        T* const p = static_cast<T*>(Alloc::malloc(sizeof(T)));
56        try { new (p) T(); }
57        catch(){ Alloc::free(p); throw; }
58        return p;
59    }
60
61    template<typename T>
62    static void destroy(T* const ptr)
63    {
64        ptr->~T();
65        Alloc::free(ptr);
66    }
67};

應用
   下面代碼中的mem_pool是一種基於自由列表機制實現的內存池,quick_object從new_delete_policy_base<mem_pool>繼承,用於演示定制new和delete的行為,_THROW_EXCEPTION宏用於屏蔽代碼,測試當對象空間分配成功但構造函數拋出異常時,對應的operator delete是否得到調用,而保證釋放內存空間,normal_object是空類,它不從new_delete_policy_base<mem_pool>繼承,用於演示對象池構造和銷毀對象的行為。
 1class quick_object : public new_delete_policy_base<mem_pool>
 2{
 3public:
 4    quick_object()
 5    {
 6#ifdef _THROW_EXCEPTION
 7        throw 0;
 8#endif
 9        cout << "quick_object()" << endl;   
10    }
11    ~quick_object()
12    {
13        cout << "~quick_object()" << endl;
14    }
15};
16
17class normal_object
18{
19public:
20    normal_object()
21    {
22        cout << "normal_object()" << endl;       
23    }
24    ~normal_object()
25    {
26        cout << "~normal_object()" << endl;
27    }
28};
29
30/**
31 *    the following code,if quick_object's construct function throw exception,then result in
32 *    c/c++ Run-time system call operator delete correspond to operator new automaticlly.
33 */
34static void unit_test_new_delete_policy()
35{   
36    quick_object* obj = NULL;
37
38    try {
39        obj = new quick_object; //call simple new
40        delete obj;             //call simple delete
41    }catch(){
42        //call simple delete
43    }
44
45    try {
46        obj = new (std::nothrow) quick_object; //call nothrow new
47        delete obj; //call simple delete
48    }catch(){
49        // call nothrow delete
50    }
51
52    try {
53        char ptr[sizeof(quick_object)];
54        obj = new (ptr) quick_object; //call placement new
55    }catch(){
56        //call placement delete
57    }
58   
59    try{
60        obj = new quick_object[10]; //call simple new[]
61        delete []obj;        //call simple delete[]
62    }catch(){
63        //call simple delete[]
64    }
65
66    try {
67        obj = new (std::nothrow) quick_object[10]; //call nothrow new[]
68        delete []obj; //call simple delete[]
69    }catch(){
70        //call nothrow delete[]
71    }
72
73    try {
74        char ptr[sizeof(quick_object[10])];
75        obj = new (ptr) quick_object[10];    //call placement new[]
76    }catch () {
77        //call placement delete[]
78    }
79}
80
81/**
82 *    class quick_object is inherited from class new_delete_policy_base<mem_pool> that has implement
83 *    operator new and delete,so that call placement new in template member construct of class obj_pool.
84 */
85static void unit_test_obj_pool()
86{
87    typedef object_pool_impl<mem_pool> obj_pool;
88
89    try{
90        quick_object* obj = obj_pool::construct<quick_object>();
91        obj_pool::destroy(obj);
92    }catch () {
93
94    }
95    //class normal_object's construct function do not throw exception.
96    normal_object* obj = obj_pool::construct<normal_object>();
97    obj_pool::destroy(obj);
98}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved