第六十九課、自定義內存管理

1、統計對象中某個成員變量的訪問次數

解決方法一:ios

#include <iostream>

using namespace std; class Test { private: int i; mutable int m_count; public: Test(int v) { i = v; m_count = 0; } void setI(int v) { i = v; m_count++; } int getI() const  //方便const對象調用
 { m_count++; return i; } int getCount() const //方便const對象調用
 { return m_count; } }; int main() { const Test t(2);//只讀對象
    cout << t.getI() << endl;//2
    cout << t.getCount() << endl;//1
    
    return 0; }
統計對象中某個成員變量的訪問次數

1.遺失的關鍵字:mutable

(1)、mutable關鍵字是爲了突破const函數的限制設計的c++

(2)、mutable關鍵字將永遠處於可改變的狀態數組

(3)、mutable關鍵字在實際項目中被嚴禁使用ide

二、mutab的深刻分析

(1)、mutable破壞了只讀對象內部的狀態函數

(2)、const成員函數保證只讀對象內部的狀態不變性spa

(3)、mutable成員變量的出現沒法保證狀態不變性設計

解決方法二:指針

#include <iostream>

using namespace std; class Test { private: int i; int * const m_count;//左數右指,const在*左邊表示指針指向的地址中的數據是常量,在右說明指針自己是常量
public: Test(int v = 0) : m_count(new int(0))//const變量要在初始化列表中進行初始化
 { i = v; } void setI(int v) { i = v; *m_count = *m_count + 1; } int getI() const  //方便const對象調用
 { *m_count = *m_count + 1;//巧妙!!!只讀成員函數裏並無改變成員變量的值
        return i; } int getCount() const //方便const對象調用
 { return *m_count; } ~Test() { delete m_count; } }; int main() { const Test t(2);//只讀對象
    cout << t.getI() << endl;//2
    cout << t.getCount() << endl;//1
    
    return 0; }
統計對象中對某個變量的訪問次數

2、new/delete的本質是c++預約義的操做符

一、c++對這兩個操做符作了嚴格的行爲定義

new:code

(1)、獲取足夠大的內存空間(默認爲堆空間對象

(2)、在獲取的空間中調用構造函數建立對象

delete:

(1)、調用析構函數銷燬對象

(2)、歸還對象所佔用的空間(默認爲堆空間)

二、c++中可以重載new/delete操做符(意義在於改變更態對象建立時的內存分配方式)

(1)、全局重載(不推薦)

(2)、局部重載(針對具體類進行重載)

三、new/delete的重載方式(都是static的)

#include <iostream>

using namespace std; class Test { private: static const unsigned int COUNT = 4;//最多分配4個Test大小
    static char c_buffer[];//分配空間
    static char c_map[];//用來標記哪一個空間能夠用
    int m_value; public: Test() { } void * operator new(unsigned int size) { void* ret = NULL; for(int i=0; i<COUNT; i++) { if( !c_map[i] ) { ret = c_buffer + i*sizeof(Test); c_map[i] = 1; cout << "succed to new a object:" << ret << endl; break; } } return ret; } void operator delete(void* p) { if(p != NULL) { char* mem = reinterpret_cast<char*>(p); int index = (mem - c_buffer) / sizeof(Test); int flag = (mem - c_buffer) % sizeof(Test);//要保證位置合法
            
            if( (flag == 0) && (0 <= index) && (index < COUNT) ) { c_map[index] = 0; cout << "succed to delete a object: " << p << endl; } } } }; char Test::c_buffer[sizeof(Test)*Test::COUNT] = {0}; char Test::c_map[COUNT] = {0}; int main() { Test* pa[5] = {0}; for(int i=0; i<5; i++) { pa[i] = new Test; cout << "new " << "pa[" << i << "]=" << pa[i] << endl; } for(int i=0; i<5; i++) { cout << "delete " << "pa[" << i << "]=" << pa[i] << endl; delete pa[i]; } return 0; } //輸出結果 /* succed to new a object:0x804a0d4 new pa[0]=0x804a0d4 succed to new a object:0x804a0d8 new pa[1]=0x804a0d8 succed to new a object:0x804a0dc new pa[2]=0x804a0dc succed to new a object:0x804a0e0 new pa[3]=0x804a0e0 new pa[4]=0 delete pa[0]=0x804a0d4 succed to delete a object: 0x804a0d4 delete pa[1]=0x804a0d8 succed to delete a object: 0x804a0d8 delete pa[2]=0x804a0dc succed to delete a object: 0x804a0dc delete pa[3]=0x804a0e0 succed to delete a object: 0x804a0e0 delete pa[4]=0 */
靜態存儲區分配空間

3、在指定地址上建立c++對象

一、重載new/delete

(1)、在類中重載new/delete操做符

(2)、在new操做符重載函數中返回指定地址

(3)、在delete操做符重載函數中標記對應的地址可用

#include <iostream> #include <string> #include <cstdlib>

using namespace std; class Test { static unsigned int c_count; static char* c_buffer; static char* c_map; int m_value; public: static bool SetMemorySource(char* memory, unsigned int size) { bool ret = false; c_count = size / sizeof(Test); ret = (c_count && (c_map = reinterpret_cast<char*>(calloc(c_count, sizeof(char))))); if( ret ) { c_buffer = memory; } else { free(c_map); c_map = NULL; c_buffer = NULL; c_count = 0; } return ret; } void* operator new (unsigned int size) { void* ret = NULL; if( c_count > 0 ) { for(int i=0; i<c_count; i++) { if( !c_map[i] ) { c_map[i] = 1; ret = c_buffer + i * sizeof(Test); cout << "succeed to allocate memory: " << ret << endl; break; } } } else { ret = malloc(size); } return ret; } void operator delete (void* p) { if( p != NULL ) { if( c_count > 0 ) { char* mem = reinterpret_cast<char*>(p); int index = (mem - c_buffer) / sizeof(Test); int flag = (mem - c_buffer) % sizeof(Test); if( (flag == 0) && (0 <= index) && (index < c_count) ) { c_map[index] = 0; cout << "succeed to free memory: " << p << endl; } } else { free(p); } } } }; unsigned int Test::c_count = 0; char* Test::c_buffer = NULL; char* Test::c_map = NULL; int main(int argc, char *argv[]) { char buffer[12] = {0}; Test::SetMemorySource(buffer, sizeof(buffer)); cout << "===== Test Single Object =====" << endl; Test* pt = new Test; delete pt; cout << "===== Test Object Array =====" << endl; Test* pa[5] = {0}; for(int i=0; i<5; i++) { pa[i] = new Test; cout << "pa[" << i << "] = " << pa[i] << endl; } for(int i=0; i<5; i++) { cout << "delete " << pa[i] << endl; delete pa[i]; } return 0; } //輸出結果 /* ===== Test Single Object ===== succeed to allocate memory: 0xbfbc38f0 succeed to free memory: 0xbfbc38f0 ===== Test Object Array ===== succeed to allocate memory: 0xbfbc38f0 pa[0] = 0xbfbc38f0 succeed to allocate memory: 0xbfbc38f4 pa[1] = 0xbfbc38f4 succeed to allocate memory: 0xbfbc38f8 pa[2] = 0xbfbc38f8 pa[3] = 0 pa[4] = 0 delete 0xbfbc38f0 succeed to free memory: 0xbfbc38f0 delete 0xbfbc38f4 succeed to free memory: 0xbfbc38f4 delete 0xbfbc38f8 succeed to free memory: 0xbfbc38f8 delete 0 delete 0 */
在指定地址分配空間

 二、new[]/delete[]和new/delete 徹底不一樣

(1)、動態對象數組的建立經過new[]完成

(2)、動態對象數組銷燬經過delete[]完成

(3)、new[]/delete[]能夠被重載,進而改變內存管理方式

注意事項:

(1)、new[]返回的地址空間可能比指望的多(緣由如二、3)

 (2)、對象數組中佔用的內存中須要保存數組信息(否則怎麼知道調用多少次構造和析構函數?)

(3)、數組信息用於肯定構造函數和析構函數的調用次數

#include <iostream> #include <string> #include <cstdlib>

using namespace std; class Test { int m_value; public: Test() { m_value = 0; } ~Test() { } void* operator new (unsigned int size) { cout << "operator new: " << size << endl; return malloc(size); } void operator delete (void* p) { cout << "operator delete: " << p << endl; free(p); } void* operator new[] (unsigned int size) { cout << "operator new[]: " << size << endl; return malloc(size); } void operator delete[] (void* p) { cout << "operator delete[]: " << p << endl; free(p); } }; int main(int argc, char *argv[]) { Test* pt = NULL; pt = new Test; delete pt; pt = new Test[5]; delete[] pt; return 0; } //輸出結果 /* operator new: 4 operator delete: 0x8463008 operator new[]: 24 operator delete[]: 0x8463018 */
new[]分配的空間比預期的多

4、小結

(1)、new/delete本質爲操做符

(2)、能夠經過全局函數重載new/delete(不推薦)

(3)、能夠針對具體類重載new/delete 

(4)、new[]/delete[]與new/delete 徹底不一樣

(5)、new[]/delete[]也是能夠被重載的操做符

(6)、new[]返回的地址空間可能比指望的多

相關文章
相關標籤/搜索