解決方法一: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關鍵字是爲了突破const函數的限制設計的c++
(2)、mutable關鍵字將永遠處於可改變的狀態數組
(3)、mutable關鍵字在實際項目中被嚴禁使用ide
(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; }
new:code
(1)、獲取足夠大的內存空間(默認爲堆空間)對象
(2)、在獲取的空間中調用構造函數建立對象
delete:
(1)、調用析構函數銷燬對象
(2)、歸還對象所佔用的空間(默認爲堆空間)
(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 */
一、重載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 */
4、小結
(1)、new/delete本質爲操做符
(2)、能夠經過全局函數重載new/delete(不推薦)
(3)、能夠針對具體類重載new/delete
(4)、new[]/delete[]與new/delete 徹底不一樣
(5)、new[]/delete[]也是能夠被重載的操做符
(6)、new[]返回的地址空間可能比指望的多