淺析智慧指標
我們知道c和c++相對於其他程式語言是相當自由的語言,給了使用者很大的許可權,比較信任使用者!它允許使用者自由分配計算機記憶體,然後使用者需手動釋放,但是這就帶來了一定的風險,要知道記憶體要是申請了不手動釋放,這塊記憶體就不會作為空閒空間來供以後使用,可想而知,編寫程式要是申請的記憶體太多(當然現在編譯器都是比較智慧的,有一定的記憶體保護機制),不釋放,就可能導致主機可用空間不足,最終結果就是宕機重啟!!!
作為向c語言自身來說,就有一些缺陷,現在我們看一個例子:
A:
int * getspace(){
static int a[100] ;
return a ;
}
B:
int * getspace(){
int *a = malloc(100);
return a ;
}
這兩個函式的功能都是相同的都是返回一個長度為100的int陣列,但相信大家都會發現一個問題,A函式是不需要手動釋放記憶體的,因為static變數的生命週期和程式的生命週期是一樣的,而B函式它malloc的記憶體必須通過free 釋放掉,而函式就是對外開放的介面,使用者只需要學會用他能實現的功能就行,不需理解它內部實現,這就是非常危險的!!!要是設計一個應用程式函式都像B函式那樣寫,那就涼了!
還有在c++中,當我們在new 一個物件時,在最後,必須呼叫delete釋放,但是這樣真的能解決問題嗎???肯定不能呀!
#include<iostream>
#include<stdlib.h>
using namespace std;
class A{
private:
int a ;
public:
A(){}
~A(){}
};
int main(){
A * s = new A();
while(1){
cout<<"好好學習,遠離王者"<<endl;
}
delete s ;
}
比如說上面一個簡單的程式,執行時,在迴圈除它就不會退出了,然後我們執行強制退出,那程式是不會執到delete那塊的,所以就記憶體洩漏了!
所以,總的來說,無論是new和delete還是malloc 和free都不是保險可行的記憶體保護策略!
所以在c++中就有了專門防止記憶體洩漏的方法,在c++98之前,用的是auto_ptr,但隨著c++的發展,這種保護方法被開發者逐漸棄用,我今天要說的是另外三種現在比較通用的新的c++智慧指標方法,是c++11新特性。
shared_ptr //可以實現相同型別指標之間的相互賦值!
unique_ptr //對於某一物件特有的指標,不能實現指標之間的相互賦值!
weak_ptr //通常和shared_ptr 一起使用,是shared_ptr 的一種弱引用(非擁有:當引用的物件活著的時候不一定存在。僅僅是當它自身存在的時的一個引用),在使用時轉換成shared_ptr。
三種方法都包含在memory.h標頭檔案中其用法示例如下:
#include<iostream>
#include<memory>
#include<mcheck.h>
using namespace std;
class A{
public:
A() {
a++ ;
cout<<"build"<<" "<<a<<endl;}
~A(){
a-- ;
cout<<"destroy"<<" "<<a<<endl;
}
void say(){
cout<<"away from kingdom game"<<endl ;
}
private:
static int a ;
};
int A::a = 0 ;
int main(){
//檢驗是否記憶體洩漏
mtrace();
shared_ptr<A>demo1(new A);
shared_ptr<A>demo2(new A);
weak_ptr <A>demo3 = demo1;
demo1->say();
demo2->say();
auto s= demo3.lock();
demo1->say();
s->say();
}
執行過程截圖:
可以發現,用上智慧指標,並沒有造成記憶體洩露問題。智慧指標用的時候就和普通指標的用法差不多。它內部實現過載了*和->運算子。
以上程式中weak_ptr作為shared_ptr的引用,在使用時需要轉化為shared_ptr。
還有unique_ptr的用法,和shared_ptr差不多,但是不能實現像指標那樣互相賦值的操作,它是一個物件特有的指標,其他unique_ptr型別的指標不能再指向該物件。用法如下:
#include<stdio.h>
#include<iostream>
#include<memory>
using namespace std;
class A{
private:
static int a ;
public:
A(){
a++ ;
cout<<"the demo built"<<a<<endl ;
}
~A(){
a-- ;
cout<<"the demo destroy"<<a<<endl ;
}
void say(){
cout<<"demo"<<endl;
}
};
int A::a = 0;
int main(){
cout<<"-------------------unique ptr----------------"<<endl ;
unique_ptr <A>demoa(new A);
unique_ptr <A>demob(new A);
//這一步是錯誤的,不能互相賦值。
// unique_ptr democ = demob;
demoa->say();
demob->say();
}
嗯,現在,就說這麼多吧!強引用和弱引用以及迴圈引用等概念還不是很熟。後面少玩遊戲,多學習!要學的還是比較多的!