標籤:let blog 調用 alt 存在 ons 地址 變數 棧記憶體
對象記憶體模型
一. 棧(Stack) VS. 堆(heap)
- 棧
- 由系統自動管理,以執行函數為單位
- 空間大小編譯時間確定(參數+局部變數)
- 函數執行時,系統自動分配一個stack
- 函數執行結束時,系統立即自動回收stack
- 堆
- 在c++中由程式員手動控制
- 手動分配new和malloc
- 手動釋放delete和free
- 具有全域性,總體無大小限制
- 容易造成記憶體泄露
1. Myclass c(10); // 棧對象,空間大小在編譯時間確定,函數執行結束,系統立即回收
2.
Myclass* func(){ Myclass c(10); return &c; //返回棧記憶體位址,指標懸浮,極端錯誤! }
3.
Myclass func(){ Myclass c(10); Aclass a(100); c.pa = &a; //指向棧(local)對象,錯! return c; }
結論: 指標指向棧對象,就要極度小心,一般會有問題!
4
Myclass* func(){ Myclass *pa = new Myclass(); return pa; //小範圍看沒問題,但違背誰分配誰釋放原則,此例接受者不知道要delete }
總結返回指標問題:
返回棧指標: 完全錯誤
返回堆積指標:釋放可能有問題 ,易造成記憶體泄露
故一般不推薦
5 堆對象記憶體模型
6. 棧對象記憶體模型
二. 變數模型與使用 (對象,指標,引用; 聲明,傳參,傳回值)
1. 聲明與符號
“*” : 聲明時,指標
用在指標前,解指標
“&”: 聲明時,引用
用在對象前,取地址
MyClass c; //對象,一定在棧上MyClass* pc; //指標,要問自己是棧指標,還是堆積指標MyClass& c2 = c; //引用,要問自己是棧引用,還是堆引用。本例為棧引用
// 舉例堆引用 Myclass *pc2 = new Myclass(); Myclass& c3 = *pc2; c3為堆引用
c = *pc; //解指標, 可指向堆對象,也可以指向棧對象 //pc指向哪裡,*pc即為指向哪裡的對象(堆/棧) //又c在棧上 再調用拷貝建構函式完成 c = *pcpc = &c; //取地址
2 傳參分析
//對象void func1(MyClass c) { // 對象往往較大,開銷大,一般不!}//指標void func2(MyClass* pc) { // 成本ok,但無法區分堆/棧,有delete問題}//引用void func3(MyClass& mc) { //推薦,不想雙向傳遞用const}
const& 為 pass by value好的替代品
void func3(const MyClass& mc) {}
調用方法:
MyClass c1;func1(c1); //調用拷貝構造func2(&c1); //不調用拷貝構造func3(c1); //不調用拷貝構造,注意參數就寫值即可,參考筆記2,傳遞者無需知道接受者的接受方式。亂加符號可能變成取地址了
3. 傳回值分析
返回對象分析:
MyClass func1() { MyClass c1; return c1; //正確,調用拷貝構造 MyClass* pc2 = new MyClass(); return *pc2; // 返回時調用拷貝構造,結束後pc2就取不到了,記憶體無法釋放,一定存在記憶體泄露}
返回指標分析:
MyClass* func2() { MyClass c1; return &c1; //極端錯誤,返回棧對象指標 MyClass* pc2 = new MyClass(); return pc2; //不推薦,可能記憶體泄露,違背誰調用誰釋放原則}
故返回指標一般不推薦
返回引用分析:
MyClass& func3() { MyClass c1; return c1; // 極端錯誤,棧對象結束就消亡了 MyClass* pc2 = new MyClass(); return *pc2; //可能存在記憶體泄露,有辦法取到pc2,但一般人不會去做,也不知道要做}
返回傳入參數的引用,ok且推薦,常見還有this指標
MyClass& func4(MyClass& c) { return c;}
C++對象記憶體模型1(堆棧模型)