由於之前也只是瞭解智能指針,要我說估計只能說個它是幹什麼的,用不了幾分鐘。
昨天花了一天時間各種百度,算是對智能指針有了一點了解,這篇文章基本就是這次分享會的PPT的copy,沒有底層的東西,多是概念。
我覺得理解智能指針需要了解它發展的三個過程:起因,經過,結果。這篇文章主要講述的是起因,經過和結果等以後工作了,實際接觸了再說吧。
起因:
1.爲什麼需要智能指針
一:內存泄露
<pre name="code" class="cpp">//內存泄露
#include <stdio.h>
#include <iostream>
using namespace std;
class A
{
public:
A(char *cstr);
A(const A &ca);
A();
~A();
A operator=(const A &ca);
private:
char *str;
};
A::A(char *cstr)
{
str = new char[20];
strcpy(str, cstr);
}
A::A(const A &ca)
{
str = new char[20];
strcpy(str, ca.str);
}
A A::operator=(const A &ca)
{
str = new char[20];
strcpy(str, ca.str);
return str;
}
A::A() : str(new char[20])
{
strcpy(str, "Welcome!");
}
A::~A()
{
delete[] str;
str = NULL;
}
int main(void)
{
A a("Hello world!");
A b(a);
A c;
c = b;
return 0;
}
{
str =new char[20];
strcpy(str, ca.str);
}
一:
A::operator=(constA &ca)
{
strcpy(str, ca.str);
}
但是前提是我們已經申請了空間。
二:
A::operator=(const A &ca)
這是個比較危險的方法,如果str沒有被初始化或者已經被delet過了,程序就會發生致命錯誤!
A::operator=(const A &ca)
這是最好的方法,可以在很多源碼中發現都是用了這種方法。但是需要注意的是str在沒有被分配前必須初始化爲NULL,因爲在未分配和初始化NULL的時候,str不一定是個空指針,還可能是一個野指針。
二:懸垂指針
#include <stdio.h>
#include <iostream>
#include <windows.h>
using namespace std;
int *p=NULL;
void fun()
{
int i=10;
p=&i;
}
int main()
{
fun();
cout<<"*p= "<<*p<<endl;//輸出p=10
Sleep(1000);
cout<<"*p= "<<*p<<endl;//輸出p=0
return 0;
}
兩次輸出的值不一樣,因爲程序發生了懸垂指針的錯誤。具體和操作系統的堆棧管理方式有關,感興趣可以去百度~2.爲什麼不自建“智能”指針
class intptr
{
private:
int* m_p;
public:
intptr(int* p){ m_p = p; }
~intptr(){ delete m_p; }
int& operator*(){ return *m_p; }
};
這就是上面想法的一個例子,當我們這樣調用的時候不會出現問題:somefunction()
{
intptr pi(new int);
*pi = 10;
int a = *pi;
}
但是如果換種方式:void somefunction()
{
intptr pt1(new int);
intptr pt2(new int);
*pt1 = 10;
pt2 = pt1;
}
問題就出現了,pt2指向了pt1所指向的內容,那麼pt2原來所指向的內容我們就無法獲取和銷燬了,這也是一種內存泄露。另外在程序塊結束後,這塊內存將要被銷燬兩次,這明顯是不符合邏輯的。經過:
1.引用計數
由於以上問題,我們又引入了引用計數這個概念。2.幾種智能指針的概述
boost::scoped_ptr、
boost::shared_ptr、
boost::scoped_array、
boost::shared_array、
boost::weak_ptr、
boost::intrusive_ptr
auto_ptr
不能作爲STL的成員(C++標準明確禁止這樣做,否則可能會碰到不可預見的結果)
不能共享所有權(不一定是缺點,有它一定的應用)
不能指向數組
不能通過賦值操作來初始化
std::auto_ptr<int> p(new int(42)); //OK
scoped_ptr
boost::scoped_ptr所管理的對象生命週期僅僅侷限於一個區間(該指針所在的"{}"之間),無法傳到區間之外,這就意味着boost::scoped_ptr對象是不能作爲函數的返回值的(std::auto_ptr可以)。
這點和std::auto_ptr類似。這個特點一方面使得該指針簡單易用。另一方面也造成了功能的薄弱——不能用於stl的容器中。
由於boost::scoped_ptr是通過delete來刪除所管理對象的,而數組對象必須通過deletep[]來刪除,因此boost::scoped_ptr是不能管理數組對象的,如果要管理數組對象需要使用boost::scoped_array類
shared_ptr
weak_ptr
3.強引用與弱引用
相對而言,弱引用當引用的對象活着的時候不一定存在。僅僅是當它存在的時候的一個引用。弱引用並不修改該對象的引用計數,這意味這弱引用它並不對對象的內存進行管理,在功能上類似於普通指針,然而一個比較大的區別是,弱引用能檢測到所管理的對象是否已經被釋放,從而避免訪問非法內存