auto_ptr和shared_ptr
http://patmusing.blog.163.com/blog/static/13583496020101824541270/
a. auto_ptr定義于頭文件memory中;
?
b. auto_ptr只能用來管理單個(gè)動(dòng)態(tài)創(chuàng)建的對(duì)象,而不能管理動(dòng)態(tài)創(chuàng)建的數(shù)組;
?
c.?和其他copy和assign不同,auto_ptr的copy和assign會(huì)改變右邊的操作數(shù),assignment符號(hào)的兩邊的auto_ptr均為左值;There is a crucially important difference between how auto_ptr and built-in pointers treat copy and assignment. When we
copy an auto_ptr or assign its value to another auto_ptr, ownership of the underlying object is transferred from the original
to the copy. The original auto_ptr is reset to an unbound state;
?
d. auto_ptr不能作為容器中的元素;
??auto_ptr的copy和assign具有析構(gòu)行為,這就是auto_ptr不能作為容器元素的原因,因?yàn)闃?biāo)準(zhǔn)庫(kù)中的容器有對(duì)元素的要求:經(jīng)
過copy或者assign后的兩個(gè)對(duì)象,必須相等;
?
e.?在判斷一個(gè)auto_ptr是否被綁定的時(shí)候,不能直接使用auto_ptr對(duì)象:
??????auto_ptr<Student> stu1(new?Student);
?????????if(stu1)
?????????{
???????????????????cout <<?"stu1 is bound"?<< endl;
?????????}
?????????else
?????????{
???????????????????cout <<?"stu1 is unbound"?<< endl;
?????????}
?????????這樣做將會(huì)導(dǎo)致compile error,應(yīng)該改為:
?????????auto_ptr<Student> stu1(new?Student);
?????????if(stu1.get())???????????????// get()獲取的是underlying對(duì)象的指針,如果被綁定則非零,如果沒有被綁定則為0
?????????{
???????????????????cout <<?"stu1 is bound"?<< endl;
?????????}
?????????else
?????????{
???????????????????cout <<?"stu1 is unbound"?<< endl;
?????????}
?
f. auto_ptr的構(gòu)造函數(shù)是explicit的,消除了隱式的類型轉(zhuǎn)換(在這里即,從指針類型到auto_ptr類型的轉(zhuǎn)換),因此不能直接將一個(gè)
指針賦給一個(gè)auto_ptr對(duì)象。如下面這樣的代碼:
?????????auto_ptr<Student> stu5 =?new?Student;
?????????stu5->printStudentInfo();
??在編譯的時(shí)候不會(huì)有問題,但會(huì)出現(xiàn)嚴(yán)重的runtime error。正確的做法應(yīng)該是:
?????????auto_ptr<Student> stu5(new?Student);
?????????stu5->printStudentInfo();
?
g.?不同用兩個(gè)auto_ptr綁定到同一個(gè)對(duì)象。
??????// stu6和stu7綁定到了同一個(gè)對(duì)象,這將會(huì)導(dǎo)致該對(duì)象被析構(gòu)兩次,將會(huì)產(chǎn)生runtime error
?????????auto_ptr<Student> stu6(new?Student("Evanligine",?"F", 8));
?????????auto_ptr<Student> stu7(stu6.get());
?????????后面一句,應(yīng)該改為:
?????????auto_ptr<Student> stu7(stu6);
?????????這樣stu6就將ownership轉(zhuǎn)交給了stu7,stu6則成為了unbound的auto_ptr。????????????
?
h.?不能用auto_ptr指向靜態(tài)資源分配對(duì)象。如下面的代碼,盡管可以通過編譯,但將會(huì)產(chǎn)生runtime error:
?????????int?ix = 10;
?????????auto_ptr<int> pint1(&ix);
?
i. auto_ptr的重要操作
auto_ptr<T> ap;???????????? ??創(chuàng)建一個(gè)未綁定的auto_ptr對(duì)象ap
auto_ptr<T> ap(p);??????? ???創(chuàng)建一個(gè)auto_ptr對(duì)象ap,它綁定了指針p所指向的對(duì)象。該構(gòu)造函數(shù)是explicit的
auto_ptr<T> ap1(ap2);??????創(chuàng)建一個(gè)auto_ptr對(duì)象ap1,它綁定到原來被ap2綁定的對(duì)象,ap2則成為未綁定的auto_ptr
ap1 = ap2;???????????????????????ap1刪除原來綁定的對(duì)象,ap2將ownership移交給ap1,ap2成為未綁定的auto_ptr
*ap??????????????????????????????????返回ap綁定的對(duì)象的引用。可以通過*給被綁定的內(nèi)在對(duì)象賦值。如下面代碼:
????????????????????????????????????????????????????????auto_ptr<int> pint(new?int(3));
????????????????????????????????????????????????????????cout << *pint << endl;???????????????????????????//?輸出3
????????????????????????????????????????????????????????*pint = 100;
????????????????????????????????????????????????????????cout << *pint << endl;???????????????????????????//?輸出100
ap->????????????????????????????????返回被ap綁定的對(duì)象的指針
ap.reset(p)???????????????????????如果指針p和ap綁定的內(nèi)存對(duì)象的指針不相同,那么ap刪除被其綁定的內(nèi)存對(duì)象,改而綁定p所
???????? 指向的對(duì)象.
ap.release() ? ? ? ? ? ? ? ? ? ?ap內(nèi)部指向?yàn)镹ULL,但是原來所指內(nèi)存并不會(huì)主動(dòng)釋放,要手動(dòng)去釋放調(diào)用delete
ap.get()???????????????????????????返回ap所綁定對(duì)象的指針
#include <iostream> #include <memory>using namespace std;class A {public:int a;A(int aa):a(aa) {cout << "constructing A = " << a<<endl;}~A() {cout << "deconstruct A = " << a <<endl;}void fun() {cout << "print A = " << a <<endl;} };int main() {{auto_ptr<A> p1(new A(1));if(p1.get()) {p1.get()->a = 2;(*p1.get()).a = 3;p1.get()->fun();(*p1).a = 4;//*p1就是得到了原對(duì)象的引用(*p1).fun();p1->a = 5;//p1->返回的是原對(duì)象的指針p1->fun();auto_ptr<A> p2 = p1;cout << p1.get()<<endl;p2->fun();//p2.release();//比較危險(xiǎn),只是p2指向NULL,但是原來的內(nèi)存不釋放,即使出了這個(gè)作用域//cout << "releas p2\n";//cout << p2.get()<<endl;p2.reset(new A(12));p2.reset();//主動(dòng)釋放內(nèi)存cout << "bounded\n";}else{cout << "unbound\n";}}cout << "out of area\n";return 0; }
1、auto_ptr不能共享所有權(quán)。
2、auto_ptr不能指向數(shù)組
3、auto_ptr不能作為容器的成員。
4、不能通過賦值操作來初始化auto_ptr
std::auto_ptr<int>?p(new?int(42));?????//OK
std::auto_ptr<int>?p?=?new?int(42);????//ERROR
這是因?yàn)閍uto_ptr?的構(gòu)造函數(shù)被定義為了explicit
5、不要把a(bǔ)uto_ptr放入容器
對(duì)于shared_ptr先看個(gè)例子
如果是p1->m_other = p2;
先要釋放p2的資源,但是p2被引用了兩次,所以釋放只是把引用次數(shù)變?yōu)?
在釋放p1的資源,先進(jìn)入析構(gòu)函數(shù),釋放p1,在析構(gòu)p1的內(nèi)部成員變量,就是p2,這時(shí)p2發(fā)現(xiàn)自己的引用次數(shù)為1了,再調(diào)用p2的析構(gòu)
如果是p2->m_other = p1
先進(jìn)入p2的析構(gòu)函數(shù),再去析構(gòu)p2的成員變量m_other,發(fā)現(xiàn)其引用次數(shù)為2,所以只是講其引用次數(shù)變?yōu)?
在進(jìn)入p1的析構(gòu)函數(shù)
循環(huán)引用
class B;class A {public:int a;A(int aa):a(aa) {cout << "constructing A = " << a<<endl;}~A() {cout << "deconstruct A = " << a <<endl;}void fun() {cout << "print A = " << a <<endl;}tr1::shared_ptr<B> m_other; };class B {public:int b;B(int bb):b(bb) {cout << "constructing B = " << b<<endl;}~B() {cout << "deconstruct B = " << b <<endl;}void fun() {cout << "print B = " << b <<endl;}tr1::shared_ptr<A> m_other; };int main() {tr1::weak_ptr<A> wp;{tr1::shared_ptr<A> pa(new A(1));tr1::shared_ptr<B> pb(new B(2));pb->m_other = pa;pa->m_other = pb;} }output:
constructing A = 1
constructing B = 2
bounded
out of area
都沒進(jìn)入析構(gòu)函數(shù)釋放資源
先釋放pb,發(fā)現(xiàn)pb指向的元素被引用兩次,所以只是將引用次數(shù)變?yōu)?
后釋放pa,同理,將引用次數(shù)變?yōu)?
這里就有了內(nèi)存泄露
需要用weak_ptr打破循環(huán)引用
把class A 或者B中任何一個(gè)或者兩個(gè)m_other變?yōu)閣eak_ptr就可以解決上述問題
weak_ptr
weak_ptr本身不具有指針的行為,例如你不能對(duì)一個(gè)weak_ptr來進(jìn)行*或者->操作。它通常用來和shared_ptr配合使用。
weak_ptr作為一個(gè)”shared_ptr的觀察者”能夠獲知shared_ptr的引用計(jì)數(shù),還可以獲知一個(gè)shared_ptr是否已經(jīng)被析構(gòu)了。單沖這一點(diǎn)來說,就一點(diǎn)不weak了
構(gòu)造weak_ptr
有兩種方法可以構(gòu)造一個(gè)weak_ptr
1、 從shared_ptr構(gòu)造而來。這種情況不會(huì)增加shared_ptr的引用計(jì)數(shù)。當(dāng)然會(huì)增加另一個(gè)計(jì)數(shù),這個(gè)放到下一篇中講。
2、 從另一個(gè)weak_ptr拷貝。
也就是說weak_ptr不可能脫離shared_ptr而存在。
expired()
返回布爾,當(dāng)返回true的時(shí)候表示,weak_ptr關(guān)聯(lián)的shared_ptr已經(jīng)被析構(gòu)了。
int _tmain(int argc, _TCHAR* argv[])
{
shared_ptr<foo> fptr=shared_ptr<foo>(new foo(1,2));
weak_ptr<foo> wptr=fptr;
fptr.reset();
if(wptr.expired())
{
cout<<”wptr has expired”<<endl;
}
system(“pause”);
return 0;
}
lock()
從當(dāng)前的weak_ptr創(chuàng)建一個(gè)新的shared_ptr。如果此時(shí)expired()返回true時(shí),創(chuàng)建的shared_ptr中將保存一個(gè)null_ptr。
use_count()
返回當(dāng)前關(guān)聯(lián)的shared_ptr的引用計(jì)數(shù)是多少。expired()返回true時(shí),該函數(shù)返回0。
weak_ptr使用場(chǎng)景
weak_ptr的特性是:weak_ptr不會(huì)增加shared_ptr的引用計(jì)數(shù),所以weak_ptr通常用來解決shared_ptr無法解決的問題,例如環(huán)形引用。weak_ptr常見的使用場(chǎng)景有這么幾個(gè):
1、 想管理某些資源,但是又不想增加引用計(jì)數(shù),那么就可以保存weak_ptr。
2、 當(dāng)知道了有環(huán)形引用后,可以使用weak_ptr。例如上面的例子可以改為這樣:
class CParent
{
public:
shared_ptr< CChild > children;
};
class CChild
{
public:
weak_ptr< CParent > parent;
};
int main()
{
{
shared_ptr< CParent > pA(new CParent);
shared_ptr< CChild > pB(new CChild);
pA-> children =pB;
pB-> parent =pA;
}
}
3、 某些情況下,需要知道某個(gè)shared_ptr是否已經(jīng)釋放了。
總結(jié)
1、 在遺留代碼上如果要引入shared_ptr要謹(jǐn)慎!shared_ptr帶來的不確定性可能要比帶來的便利性大的多。
2、 使用shared_ptr并不是意味著能偷懶。反而你更需要了解用shared_ptr管理的對(duì)象的生命周期應(yīng)該是什么樣子的,是不是有環(huán)形引用,是不是有線程安全問題,是不是會(huì)在某個(gè)地方意外的被某個(gè)東西hold住了。
3、 一個(gè)對(duì)象如何使用shared_ptr管理那么最好全部使用shared_ptr來管理,必要的時(shí)候可以使用weak_ptr。千萬不要raw ptr和智能指針混用
4、 多線程讀寫同一個(gè)shared_ptr的時(shí)候,可以先加鎖拷貝一份出來,然后解鎖即可。
http://www.sssa2000.com/?p=915
總結(jié)
以上是生活随笔為你收集整理的auto_ptr和shared_ptr的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 二叉树的定义
- 下一篇: Windows8.1 64bit环境下搭