柚子快報激活碼778899分享:C++RAII內(nèi)存管理技術(shù)
柚子快報激活碼778899分享:C++RAII內(nèi)存管理技術(shù)
文章目錄
一.什么是RAII內(nèi)存管理技術(shù)?二.智能指針unique_ptrshared_ptr循環(huán)引用問題weak_ptr
一.什么是RAII內(nèi)存管理技術(shù)?
C++在引入異常機制后,代碼執(zhí)行流的跳轉(zhuǎn)變得難以預(yù)料,如果使用普通的指針進行內(nèi)存管理,很難避免內(nèi)存泄漏的問題(執(zhí)行流跳轉(zhuǎn)導致堆區(qū)資源無法被釋放)RAII技術(shù)指的是利用對象的生命周期來管理內(nèi)存資源,就堆區(qū)內(nèi)存資源的管理而言,指的就是:將指針封裝在類中,在類對象構(gòu)造時獲取堆區(qū)資源,當類對象生命周期結(jié)束時,通過類對象的析構(gòu)函數(shù)自動完成堆區(qū)資源的釋放,這樣的類對象就是智能指針
智能指針可以有效地避免開發(fā)中出現(xiàn)內(nèi)存泄漏的問題,同時為開發(fā)者省去了很多時間和精力
二.智能指針
C++11標準庫中智能指針主要分為三大類:
unique_ptr
unique_ptr對象之間不允許進行拷貝,即一個unique_ptr對象管理一塊堆區(qū)內(nèi)存資源,是一一對應(yīng)的關(guān)系unique_ptr的簡單實現(xiàn)原理:
//不允許拷貝的智能指針
//delfunc是堆區(qū)資源釋放函數(shù),用于調(diào)用delete或者delete[]
template
class unique_ptr
{
public:
unique_ptr(T * ptr = nullptr)
:_ptr(ptr)
{}
~unique_ptr()
{
if (_ptr)
{
delfunc del;
del(_ptr);
std::cout << "delete" << std::endl;
}
}
//讓智能指針可以像指針一樣被使用
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
//禁止unique_ptr對象間的拷貝
unique_ptr(const unique_ptr
unique_ptr
private:
T* _ptr;
};
使用指針管理堆區(qū)資源時,我們會讓其指向單個對象或者對象數(shù)組,單個對象用delete完成資源釋放,而對象數(shù)組要采用delete[]完成資源釋放.unique_ptr的類模板參數(shù)delfunc的設(shè)計目的就是為了區(qū)分上述兩種情況,讓使用者通過設(shè)計仿函數(shù)的方式在delete和delete[]之間做選擇
shared_ptr
shared_ptr是允許進行拷貝的智能指針,然而shared_ptr對象之間發(fā)生拷貝時,就會出現(xiàn)多個智能指針對象同時管理同一塊堆區(qū)內(nèi)存的情況,shared_ptr通過引用計數(shù)的技術(shù)避免了同一塊堆區(qū)資源被釋放多次的情況出現(xiàn):引用計數(shù)的實現(xiàn)思路:
在shared_ptr內(nèi)部封裝一個指針int * recount用來維護引用計數(shù)變量每當一個shared_ptr對象進行構(gòu)造并申請堆區(qū)資源時,同時在堆區(qū)申請一個int變量作為該shared_ptr對象所指向的堆區(qū)資源的引用計數(shù)變量每當shared_ptr被拷貝時,連同int * recount一起拷貝,然后讓引用計數(shù)變量加一即可(賦值重載的實現(xiàn)還要考慮引用計數(shù)變量減一和堆區(qū)資源釋放的問題)每當shared_ptr析構(gòu)時,引用計數(shù)變量減一,若引用計數(shù)變量減為0,則釋放堆區(qū)資源 shared_ptr的簡單實現(xiàn)原理:
//允許拷貝的智能指針,利用引用計數(shù)解決內(nèi)存管理沖突
//delfunc是堆區(qū)資源釋放函數(shù),用于調(diào)用delete或者delete[]
template
class shared_ptr
{
public:
//構(gòu)造智能指針(同時創(chuàng)建引用計數(shù)變量)
shared_ptr(T* ptr = nullptr)
:_ptr(ptr),
_recount(new int(1))
{}
shared_ptr(const shared_ptr
: _ptr(shptr._ptr),
_recount(shptr._recount)
{
//智能指針拷貝增加引用計數(shù)
(*_recount)++;
}
shared_ptr
{
if (_ptr != shptr._ptr)
{
//智能指針指向改變,其先前指向的堆區(qū)內(nèi)存和引用計數(shù)變量需要處理
Release();
//完成智能指針拷貝并增加引用計數(shù)
_ptr = shptr._ptr;
_recount = shptr._recount;
++(*_recount);
}
return (*this);
}
~shared_ptr()
{
Release();
}
//讓智能指針可以像指針一樣被使用
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
T* getptr() const
{
return _ptr;
}
private:
//將資源釋放函數(shù)進行封裝,方便復用
//引用計數(shù)減一,若引用計數(shù)減為0則釋放資源
void Release()
{
//引用計數(shù)減一
--(*_recount);
//引用計數(shù)為0則釋放資源
if (*_recount == 0)
{
if (_ptr)
{
delfunc del;
del(_ptr);
std::cout << "delete" << std::endl;
}
//同時注意釋放引用計數(shù)變量
delete _recount;
}
}
private:
T* _ptr;
int* _recount;
};
shared_ptr類內(nèi)部同時還要解決引用計數(shù)變量帶來的線程安全的問題,這里暫不討論
循環(huán)引用問題
shared_ptr用在自引用結(jié)構(gòu)體中會出現(xiàn)對象無法析構(gòu)的問題:
template
class deletefunc
{
public:
void operator()(T* ptr)
{
delete ptr;
}
};
// 循環(huán)引用
struct ListNode
{
int _val;
shared_ptr
shared_ptr
~ListNode()
{
cout << "~ListNode()" << endl;
}
};
// 循環(huán)引用
void test_shared_cycle()
{
share_ptr
share_ptr
n1->_next = n2;
n2->_prev = n1;
}
當test_shared_cycle()函數(shù)執(zhí)行完后,兩個鏈表節(jié)點都無法正常析構(gòu),shared_ptr引發(fā)了循環(huán)引用的問題:n1節(jié)點的析構(gòu)依賴于n2節(jié)點中_prev指針的析構(gòu),n2節(jié)點中_prev指針的析構(gòu)依賴于n2節(jié)點的析構(gòu),n2節(jié)點的析構(gòu)又依賴于n1節(jié)點中_next指針的析構(gòu), n1節(jié)點中_next指針的析構(gòu)又依賴于n1節(jié)點的析構(gòu).如此往復構(gòu)成了循環(huán)的依賴關(guān)系導致兩個節(jié)點都無法被釋放.weak_ptr就是為了解決循環(huán)引用問題而設(shè)計的
weak_ptr
weak_ptr智能指針不參與堆區(qū)內(nèi)存的申請和釋放,也不會增加特定內(nèi)存塊的引用計數(shù)(其功能和普通指針差不多),weak_ptr支持以shared_ptr為引用形參的拷貝構(gòu)造和賦值weak_ptr簡單實現(xiàn)原理:
//用于配合share_ptr的使用用于循環(huán)引用的場景
//delfunc是堆區(qū)資源釋放函數(shù),用于調(diào)用delete或者delete[]
//weak_ptr不參與資源的申請和釋放
template
class weak_ptr
{
public:
weak_ptr()
:_ptr(nullptr)
{}
~weak_ptr()
{}
weak_ptr(const weak_ptr
:_ptr(wptr._ptr)
{}
weak_ptr(const share_ptr
:_ptr(shptr.getptr())
{}
weak_ptr
{
_ptr = wptr._ptr;
return (*this);
}
weak_ptr
{
_ptr = shptr.getptr();
return (*this);
}
//讓智能指針可以像指針一樣被使用
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
private:
T* _ptr;
};
在自引用結(jié)構(gòu)體中采用weak_ptr就可以避免出現(xiàn)循環(huán)引用的問題
柚子快報激活碼778899分享:C++RAII內(nèi)存管理技術(shù)
好文推薦
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。