“獨占型”指標unique_ptr
unique_ptr 指標指向的堆記憶體無法同其它 unique_ptr 共享,每個 unique_ptr 指標都獨自擁有對其所指堆記憶體空間的所有權,被定義在頭檔案<memory>中,并且使用std命名空間
構造unique_ptr
空構造
std::unique_ptr<int> p1();
std::unique_ptr<int> p2(nullptr);
接管已有指標
std::unique_ptr<int> p3(new int);
由此就創建出了一個 p3 智能指標,其指向的是可容納 1 個整數的堆存盤空間
移動構造
std::unique_ptr<int> p4(new int);
// std::unique_ptr<int> p5(p4);//錯誤,堆記憶體不共享
std::unique_ptr<int> p5(std::move(p4));//正確,呼叫移動建構式
對于呼叫移動建構式的 p4 和 p5 來說,p5 將獲取 p4 所指堆空間的所有權,而 p4 將變成空指標(nullptr)
功能函式
release()
釋放當前 unique_ptr 指標對所指堆記憶體的所有權,但該存盤空間并不會被銷毀
reset(p)
其中p表示一個普通指標,如果p為nullptr,則當前unique_ptr也變成空指標;反之,則該函式會釋放當前unique_ptr指標指向的堆記憶體(如果有),然后獲取p所指堆記憶體的所有權(p為nullptr)
工廠函式
在C++11標準庫中,并沒有提供unique_ptr的make_unique工廠函式(C++14提供了),但是在boost庫中,對其的工廠函式也做了補充
C++14
auto p = std::make_unique<int>(10);
assert(p && *p == 10);
使用boost庫中的make_unique
首先需要包含頭檔案<boost/smart_ptr/make_unique.hpp>,使用命名空間boost
#include <boost/smart_ptr/make_unique.hpp>
auto p = boost::make_unique<int>(10);
assert(p && *p == 10);
定制洗掉器
默認情況下,unique_ptr指標采用std::default_delete<T>方法釋放堆記憶體,也可以自定義符合實際場景的釋放規則,和 shared_ptr 指標不同,為 unique_ptr 自定義釋放規則,只能采用函式物件的方式,例如:
//自定義的釋放規則
struct myDel
{
void operator()(int *p) {
delete p;
}
};
std::unique_ptr<int, myDel> p6(new int, myDel());
“共享”指標shared_ptr
boost庫中的shared_ptr,被收納為C++新標準中的shared_ptr,可以自由地拷貝和賦值,當沒有代碼在使用它時,才會自行析構,
基本概念
參考計數:顧名思義,該指標被參考的次數
構造shared_ptr
空構造
shared_ptr() // 創建一個空智能指標,其原始指標就是nullptr
接管原始指標
shared_ptr(T * p) // 從已有的指向T型別地指標p處接管記憶體,同時參考計數加一
接管智能指標
shared_ptr(shared_ptr conster&r) operator=
// 從另一個智能指標構造,參考計數加一,相當于和原來的shared_ptr共同管理一塊記憶體
指定解構式的智能指標
shared_ptr(T * p, D d)
// 其構造程序類似于(2),但是使用了D d作為指定的解構式,在后面章節會講到
功能函式
reset()
將參考計數減一,它也可以帶引數,引數型別和建構式相似,相當于先將參考計數減一,再去接管另一個指標
unique()和use_count()
unique()在shared_ptr是指標的唯一所有者時為true,use_count()回傳當前指標的參考計數
工廠函式make_shared
make_shared()函式可以接收若干個引數,如何傳遞給型別T的建構式(在構造物件時很有用),然后創建一個shared_ptr<T>的物件并回傳,通常使用工廠函式創建物件比直接創建shared_ptr物件的方式更快且更高效
定制洗掉器
shared_ptr(Y*p,Dd)的第一個引數是要被管理的指標,它的含義與其他建構式的引數相同,而第二個引數則告訴shared_ptr在析構時不要使用delete來操作指標p,而要用d來操作,即把deletep換成d(p)
在這里洗掉器d可以是一個函式物件,也可以是一個函式指標,只要它能夠像函式那樣被呼叫,使得d(p)成立即可,對洗掉器的要求是它必須可拷貝,其行為也必須像delete那樣,不能拋出例外,為了配合洗掉器的作業,shared_ptr提供一個自由函式get_deleter(),它能夠回傳內部的洗掉器指標,有了洗掉器的概念,我們就可以用shared_ptr實作管理任意資源,只要這種資源提供了它自己的釋放操作,shared_ptr就能夠保證它自動釋放,
舉例:假設有一組檔案操作函式,使用file_t:
class file_t{...};
// open file
file_t * open_file()
{
cout << "open file" <<endl;
...
return new file_t;
}
// close file
void close_file(file_t * s)
{
cout << "close file" <<endl;
...
}
那么對檔案指標的釋放操作就應該是close_file(),而不是delete,在這里,洗掉器close_socket()是一個自由函式,因此只需要把函式名傳遞給shared_ptr即可,也可以在函式名前加上取地址運算子“&”,其效果是等價的:
file_t * s = open_socket();
// 直接傳入洗掉器
shared_ptr<file_t> p(s, &close_file);
// 等價操作
// shared_ptr<file_t> p(s, &close_file);
用法示例
shared_ptr被包含在
#include <boost/smart_ptr.hpp>
using namespace boost;
shared_ptr()可以在任何情況下接手new的分配結果,其也提供基本的執行緒安全訪問,可以被多個執行緒安全地讀取
// 接管原始指標
shared_ptr<int> sp(new int(10));
// 此時shared_ptr是指標唯一的額持有者
assert(sp.unique());
// 拷貝構造
shared_ptr<int> sp1(sp);
// shared_ptr<int> sp1 = sp;
assert(sp == sp1 && sp.use_count() == 2);
// 使用解參考運算子操作被指物件
*sp1 = 100;
// 停止使用shared_ptr
sp.reset();
// 使用工廠函式構造
auto sp2 = make_shared<string>("make shared");
auto sp3 = make_shared<vector<int>>(10, 2);
assert(sp3 -> size() == 10);
“弱”指標weak_ptr
因為它不具有普通指標的行為,沒有多載operator*和->,它的最大作用在于協助shared_ptr作業,它只負責觀測資源的使用情況,
建構式
weak_ptr被設計為與shared_ptr協同作業,它的構造和構造不會使shared_ptr的參考計數增加或減少,它可以從一個shared_ptr或者weak_ptr構造
shared_ptr<int> sp(new int(10));
assert(sp.use_count() == 1);
weak_ptr<int> wp(sp);
assert(wp.use_count() == 1);
assert(!wp.empty());
功能函式
weak_ptr沒有多載operator*和->,因為它不共享指標,不能操作資源,這正是它“弱”的原因,但它可以使用一個非常重要的成員函式lock()從被觀測的shared_ptr獲得一個可用的shared_ptr物件,把“弱”關系轉換為“強”關系,從而操作資源,但當表示指標是否有效的expired()==true時,lock()函式將回傳一個存盤空指標的shared_ptr,
// 接上例
if(!wp.expired())
{
// 獲得一個shared_ptr
shared_ptr<int> sp2 = wp.lock();
*sp2 = 100;
assert(wp.use_count() == 2);
}
assert(wp.use_count() == 1);
// 智能指標失效
sp.reset();
assert(wp.expired());
// weak_ptr將獲得一個空指標
assert(!wp.lock());
物件自我管理
weak_ptr的一個重要用途是獲得this指標的shared_ptr,使物件自己能夠生產shared_ptr管理自己:物件使用weak_ptr觀測this指標,這并不影響參考計數,在需要的時候就呼叫lock()函式,回傳一個符合要求的shared_ptr供外界使用,
這個解決方案是一種慣用法,在頭檔案<boost/enable_shared_from_this.hpp>里定義一個助手類enable_shared_from_this<T>,它的宣告摘要如下:
template<class T>
class enable_shared_from_this // 輔助類,需要繼承使用
{
public:
// 工廠函式,產生this指標的shared_ptr
shared_ptr<T> shared_from_this();
};
使用weak_ptr的時候只需要讓想被shared_ptr管理的類繼承它即可,成員函式shared_from_this()會回傳this指標的shared_ptr,例如:
class self_shared: public enable_shared_from_this<self_shared>
{
public:
self_shared(int n):num(n){}
int num;
void print()
{
cout << "self_shared:" << num << endl;
}
};
int main()
{
auto sp = make_shared<self_shared>(313);
sp -> print();
auto p = sp -> shared_from_this();
p -> num = 100;
p -> print();
}
【注意事項】不能對一個未被shared_ptr管理的物件使用shared_from_this操作獲取shared_ptr,否則會產生未定義的錯誤,
// 錯誤用法
self_shared ss;
auto p = ss.shared_from_this();
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/285512.html
標籤:C++
上一篇:1638圖形
