shared_ptr 使用詳解 (C++11)
熟悉了unique_ptr 後,其實我們發現unique_ptr 這種排他型的內存管理並不能適應所有情況,有很大的侷限!如果需要多個指針變量共享怎麼辦?
如果有一種方式,可以記錄引用特定內存對象的智能指針數量,當複製或拷貝時,引用計數加1,當智能指針析構時,引用計數減1,如果計數爲零,代表已經沒有指針指向這塊內存,那麼我們就釋放它!這就是 shared_ptr 採用的策略!
構造函數
shared_ptr sp ; //空的shared_ptr,可以指向類型爲T的對象
shared_ptr sp1(new T()) ;//定義shared_ptr,同時指向類型爲T的對象
shared_ptr<T[]> sp2 ; //空的shared_ptr,可以指向類型爲T[的數組對象 C++17後支持
shared_ptr<T[]> sp3(new T[]{…}) ;//指向類型爲T的數組對象 C++17後支持
shared_ptr sp4(NULL, D()); //空的shared_ptr,接受一個D類型的刪除器,使用D
釋放內存
shared_ptr sp5(new T(), D()); //定義shared_ptr,指向類型爲T的對象,接受一個D 類型的刪除器,使用D刪除器來釋放內存
初始化
方式一 構造函數
shared_ptrr up1(new int(10)); //int(10) 的引用計數爲1
shared_ptrr up2(up1); //使用智能指針up1構造up2, 此時int(10) 引用計數爲2
方式二 使用make_shared 初始化對象,分配內存效率更高
make_shared函數的主要功能是在動態內存中分配一個對象並初始化它,返回指向此對象的shared_ptr; 用法:
make_shared<類型>(構造類型對象需要的參數列表);
shared_ptr p4 = make_shared(2); //多個參數以逗號’,'隔開,最多接受十個
shared_ptr p4 = make_shared(“字符串”);
demo 代碼(一)
#include <iostream>
#include <stdio.h>
#include <memory>
using namespace std;
class Person
{
public:
Person(int v)
{
this->no = v;
cout << "Construct" << no << endl;
}
~Person()
{
cout << "Destruct" << no << endl;
}
private:
int no;
};
int main(void)
{
shared_ptr<Person> sp1; /* 空的shared_ptr, 可以指向類型爲T的對象 */
shared_ptr<Person> sp2(new Person(2)); /* 定義shared_ptr, 同時指向類型爲T的對象 */
cout << "sp1 ref_counter: " << sp1.use_count() << endl;
cout << "sp2 ref_counter: " << sp2.use_count() << endl; /* 當前管控Person(2) 的共享指針的數量 */
sp1 = sp2;
cout << "after sp1 = sp2, sp2 ref_counter: " << sp2.use_count() << endl;
shared_ptr<Person> sp3(sp1);
cout << "after sp3(sp1), sp2 ref_counter: " << sp2.use_count() << endl;
system("pause");
return 0;
}
運行結果:
demo 代碼(二)
#include <iostream>
#include <stdio.h>
#include <memory>
using namespace std;
class Person
{
public:
Person(int v)
{
this->no = v;
cout << "Construct" << no << endl;
}
~Person()
{
cout << "Destruct" << no << endl;
}
private:
int no;
};
int main(void)
{
shared_ptr<Person> sp1; /* 空的shared_ptr, 可以指向類型爲T的對象 */
shared_ptr<Person> sp2(new Person(2)); /* 定義shared_ptr, 同時指向類型爲T的對象 */
cout << "sp1 ref_counter: " << sp1.use_count() << endl;
cout << "sp2 ref_counter: " << sp2.use_count() << endl; /* 當前管控Person(2) 的共享指針的數量 */
sp1 = sp2;
cout << "after sp1 = sp2, sp2 ref_counter: " << sp2.use_count() << endl;
shared_ptr<Person> sp3(sp1);
cout << "after sp3(sp1), sp2 ref_counter: " << sp2.use_count() << endl;
/* 數組對象的管理 */
shared_ptr<Person[]> sp4(new Person[5]{ 3,4,5,6,7 }); /* delete [] */
system("pause");
return 0;
}
運行結果:
demo 代碼(三)
#include <iostream>
#include <stdio.h>
#include <memory>
using namespace std;
class Person
{
public:
Person(int v)
{
this->no = v;
cout << "Construct" << no << endl;
}
~Person()
{
cout << "Destruct" << no << endl;
}
private:
int no;
};
class DestructPerson
{
public:
void operator()(Person* pt)
{
cout << "DestructPerson" << endl;
delete pt;
}
};
int main(void)
{
shared_ptr<Person> sp1; /* 空的shared_ptr, 可以指向類型爲T的對象 */
shared_ptr<Person> sp2(new Person(2)); /* 定義shared_ptr, 同時指向類型爲T的對象 */
cout << "sp1 ref_counter: " << sp1.use_count() << endl;
cout << "sp2 ref_counter: " << sp2.use_count() << endl; /* 當前管控Person(2) 的共享指針的數量 */
sp1 = sp2;
cout << "after sp1 = sp2, sp2 ref_counter: " << sp2.use_count() << endl;
shared_ptr<Person> sp3(sp1);
cout << "after sp3(sp1), sp2 ref_counter: " << sp2.use_count() << endl;
/* 數組對象的管理 */
shared_ptr<Person[]> sp4(new Person[5]{ 3,4,5,6,7 }); /* delete [] */
shared_ptr<Person> sp8(new Person(8), DestructPerson()); /* 調用 DestructPerson 釋放對象 */
/* 使用 make_shared 函數模板初始化 */
shared_ptr<Person> sp9;
sp9 = make_shared<Person>(9);
cout << "after sp9 = mke_shared<Person>(9), sp9 ref_counter: " << sp9.use_count() << endl;
system("pause");
return 0;
}
運行結果:
demo 代碼(四)
#include <iostream>
#include <stdio.h>
#include <memory>
using namespace std;
class Person
{
public:
Person(int v)
{
this->no = v;
cout << "Construct" << no << endl;
}
~Person()
{
cout << "Destruct" << no << endl;
}
private:
int no;
};
class DestructPerson
{
public:
void operator()(Person* pt)
{
cout << "DestructPerson" << endl;
delete pt;
}
};
int main(void)
{
shared_ptr<Person> sp1; /* 空的shared_ptr, 可以指向類型爲T的對象 */
shared_ptr<Person> sp2(new Person(2)); /* 定義shared_ptr, 同時指向類型爲T的對象 */
cout << "sp1 ref_counter: " << sp1.use_count() << endl;
cout << "sp2 ref_counter: " << sp2.use_count() << endl; /* 當前管控Person(2) 的共享指針的數量 */
sp1 = sp2;
cout << "after sp1 = sp2, sp2 ref_counter: " << sp2.use_count() << endl;
shared_ptr<Person> sp3(sp1);
cout << "after sp3(sp1), sp2 ref_counter: " << sp2.use_count() << endl;
/* 數組對象的管理 */
shared_ptr<Person[]> sp4(new Person[5]{ 3,4,5,6,7 }); /* delete [] */
shared_ptr<Person> sp8(new Person(8), DestructPerson()); /* 調用 DestructPerson 釋放對象 */
/* 使用 make_shared 函數模板初始化 */
shared_ptr<Person> sp9;
sp9 = make_shared<Person>(9);
cout << "after sp9 = mke_shared<Person>(9), sp9 ref_counter: " << sp9.use_count() << endl;
shared_ptr<Person> sp10;
Person* p10 = new Person(10);
sp9.reset(p10);
cout << "after sp9.reset(p10), sp9 ref_counter: " << sp9.use_count() << endl;
system("pause");
return 0;
}
執行:
demo 代碼(五)
#include <iostream>
#include <stdio.h>
#include <memory>
using namespace std;
class Person
{
public:
Person(int v)
{
this->no = v;
cout << "Construct" << no << endl;
}
~Person()
{
cout << "Destruct" << no << endl;
}
int no;
};
class DestructPerson
{
public:
void operator()(Person* pt)
{
cout << "DestructPerson" << endl;
delete pt;
}
};
int main(void)
{
shared_ptr<Person> sp1; /* 空的shared_ptr, 可以指向類型爲T的對象 */
shared_ptr<Person> sp2(new Person(2)); /* 定義shared_ptr, 同時指向類型爲T的對象 */
cout << "sp1 ref_counter: " << sp1.use_count() << endl;
cout << "sp2 ref_counter: " << sp2.use_count() << endl; /* 當前管控Person(2) 的共享指針的數量 */
sp1 = sp2;
cout << "after sp1 = sp2, sp2 ref_counter: " << sp2.use_count() << endl;
shared_ptr<Person> sp3(sp1);
cout << "after sp3(sp1), sp2 ref_counter: " << sp2.use_count() << endl;
/* 數組對象的管理 */
shared_ptr<Person[]> sp4(new Person[5]{ 3,4,5,6,7 }); /* delete [] */
shared_ptr<Person> sp8(new Person(8), DestructPerson()); /* 調用 DestructPerson 釋放對象 */
/* 使用 make_shared 函數模板初始化 */
shared_ptr<Person> sp9;
sp9 = make_shared<Person>(9);
cout << "after sp9 = mke_shared<Person>(9), sp9 ref_counter: " << sp9.use_count() << endl;
shared_ptr<Person> sp10 = sp9;
Person* p10 = new Person(10);
sp9.reset(p10);
cout << "after sp9.reset(p10), sp9 ref_counter: " << sp9.use_count() << endl;
/* 交換 swap 用法 */
std::swap(sp9, sp10);
cout << "交換後, sp9: " << sp9->no << "sp10: " << sp10->no << endl;
sp9.swap(sp10);
cout << "sp9. swap(sp10) 交換後, sp9: " << sp9->no << " sp10: " << sp10->no << endl;
system("pause");
return 0;
}
運行結果:
賦值
shared_ptrr up1(new int(10)); //int(10) 的引用計數爲1
shared_ptr up2(new int(11)); //int(11) 的引用計數爲1
up1 = up2;//int(10) 的引用計數減1,計數歸零內存釋放,up2共享int(11)給up1, int(11)
的引用計數爲2
主動釋放對象
shared_ptrr up1(new int(10));
up1 = nullptr ;//int(10) 的引用計數減1,計數歸零內存釋放
或
up1 = NULL; //作用同上
重置
up.reset() ; //將p重置爲空指針,所管理對象引用計數 減1
up.reset(p1); //將p重置爲p1(的值),p 管控的對象計數減1,p接管對p1指針的管控
up.reset(p1,d); //將p重置爲p(的值),p 管控的對象計數減1並使用d作爲刪除器
交換
std::swap(p1,p2); //交換p1 和p2 管理的對象,原對象的引用計數不變
p1.swap(p2); //同上
使用陷阱
shared_ptr作爲被管控的對象的成員時,小心因循環引用造成無法釋放資源!
#include <stdio.h>
#include <iostream>
#include <string>
#include <memory>
#include <vector>
using namespace std;
class girl;
class boy
{
public:
boy()
{
cout << "boy construct!" << endl;
}
~boy()
{
cout << "boy destruct!" << endl;
}
void set_girl_friend(shared_ptr<girl>& g)
{
this->girl_friend = g;
}
private:
shared_ptr<girl> girl_friend;
};
class girl
{
public:
girl()
{
cout << "girl construct !" << endl;
}
~girl()
{
cout << "girl destruct!" << endl;
}
void set_boy_friend(shared_ptr<boy>& b)
{
this->boy_friend = b;
}
private:
shared_ptr<boy> boy_friend;
};
void use_trap()
{
shared_ptr<girl> sp_girl(new girl()); /* 白娘子 */
shared_ptr<boy> sp_boy(new boy()); /* 許仙 */
sp_girl->set_boy_friend(sp_boy);
sp_boy->set_girl_friend(sp_girl);
}
int main()
{
use_trap();
system("pause");
return 0;
}
結語:
這時間, 快高考了!!!
時間: 2020-07-03