(原創)c++11改進咱們的程序之垃圾回收

  c#和java中有自動垃圾回收機制,.net運行時和java虛擬機能夠管理分配的堆內存,在對象失去引用時自動回收,所以在c#和jva中,
內存管理不是大問題。c++語言沒有垃圾回收機制,必須本身去釋放分配的堆內存,不然就會內存泄露。
  我相信大部分c++開發人員都遇到過內存泄露的問題,而查找內存泄露的問題每每要花大量的精力。要解決這個讓人頭疼的問題可
以採起一些辦法,最有效的辦法是使用智能指針!使用智能指針就不會擔憂內存泄露的問題了,由於智能指針能夠自動刪除刪除分
配的內存。java

  智能指針是指向動態分配(堆)對象指針,用於生存期控制,可以確保自動正確的銷燬動態分配的對象,防止內存
泄露。它的一種通用實現技術是使用引用計數。每次使用它,內部的引用計數加1,每次析構一次,內部引用計數減1,減爲0時,刪
除所指向的堆內存。ios

c++11以前,c++沒有內置智能指針,以前只能藉助於boost的智能指針或者本身發明輪子。c++11如今內置的智能指針,使咱們能夠
很方便的使用智能指針了。c++11中的智能指針包括:c++

  • std::shared_ptr
  • std::unique_ptr
  • std::weak_ptr

std::shared_ptrc#

std::shared_ptr使用引用計數. 每個shared_ptr的拷貝都指向相同的內存。 在最後一個shared_ptr析構的時候, 內存纔會被釋
放。
咱們看看shared_ptr如何使用吧。
1.初始化安全

//智能指針的初始化
std::shared_ptr<int> p(new int(2));
std::shared_ptr<int> p2 = p;
std::shared_ptr<BaseConnector> m_connt = make_shared<Connector>(m_ios, m_strIP, m_port);

經過構造函數、賦值函數或者make_shared函數初始化智能指針。
智能指針初始化能夠指定刪除器函數

void DeleteIntPtr(int* p)
{
delete p;
}

std::shared_ptr<int> p(new int, DeleteIntPtr);
p的引用計數爲0時會自動調用刪除器DeleteIntPtr

2.智能指針中的原始指針,經過get獲取
char* pData = pBuf.get();this

3.注意事項。智能指針雖然能自動管理堆內存,可是它有很多陷阱,使用時須要注意:spa

1.不要把一個原生指針給多個shared_ptr管理
.net

int* ptr = new int;
shared_ptr<int> p1(ptr);
shared_ptr<int> p2(ptr); //logic error
致使ptr被刪除兩次

2.不要把this指針給shared_ptr
3.不要在函數實參裏建立shared_ptr
function ( shared_ptr<int>(new int), g( ) ); //有缺陷
可能的過程是先new int,而後調g( ),g( )發生異常,shared_ptr<int>沒有建立,int內存泄露
shared_ptr<int> p(new int());
f(p, g()); 
4.對象內部生成this的shared_ptr  指針

enable_shared_from_this 類,在該類中定了成員函數 shared_from_this() ,返回shared_ptr<T> 。這個函數僅在 shared_ptr<T> 的構造函數被調用以後才能使用。緣由是 enable_shared_from_this::weak_ptr 並不在構造函數中設置(此處的構造函數指的是類型 T 的構造函數),而是在 shared_ptr<T> 的構造函數中設置(此處的構造函數指的是類型 shared_ptr<T> 的構造函數)。

若不使用 shared_from_this() 成員函數,將this指針構造了一個shared_ptr,外面建立的對象自己的shared_ptr也管理了this資源,在析構時則會發生兩次析構;

class Y: public std::enable_shared_from_this<Y>
{
boost::shared_ptr<Y> GetSelf()
{
return shared_from_this();
}
};

boost::shared_ptr<Y> spy(new Y)
boost::shared_ptr<Y> p = spy->GetSelf(); //OK

5.shared_ptr做爲對象的成員時,當心因循環引用形成沒法釋放資源。

struct A;
struct B;
struct A
{
std::shared_ptr<B> m_b;
};

struct B
{
std::shared_ptr<A> m_a;
};

std::shared_ptr<A> ptrA(new A);
std::shared_ptr<B> ptrB(new B);
ptrA->m_b = ptrB;
ptrB->m_a = ptrA;

ptrA和ptrB相互引用,離開做用域時引用計數都爲1,致使內存沒有被釋放,解決辦法是把A和B任何一個的成員變量改成weak_ptr
解決辦法是把A和B任何一個的成員變量改成weak_ptr

struct B
{
std::weak_ptr<A> m_a;
};

ptrB->m_a不會增長A對象的引用計數,所以A對象離開做用域時,引用計數爲0,m_b的引用計數減一,b離開做用域後引用計數由1減爲0.

std::weak_ptr
弱引用指針,用來監視智能指針,不會使引用計數加1。在訪問所引用的對象前必須先轉換爲 std::shared_ptr。

用來表達臨時全部權的概念:當某個對象只有存在時才須要被訪問,並且隨時可能被他人刪除時,可使用

來跟蹤該對象。須要得到臨時全部權時,則將其轉換爲 std::shared_ptr,此時若是原來的std::shared_ptr 被銷燬,則該對象的生命期將被延長至這個臨時的 std::shared_ptr 一樣被銷燬爲止。

還能夠用來避免 std::shared_ptr 的循環引用。

std::weak_ptr<int> gw; 
void f()
{
if (auto spt = gw.lock()) { // Has to be copied into a shared_ptr before usage
std::cout << *spt << "\n";
}
else {
std::cout << "gw is expired\n";
}
}

int main()
{
{
auto sp = std::make_shared<int>(42);
gw = sp;
f();
}
f();
}
輸出
42 
gw is expired

 std::unique_ptr

unique_ptr不會共享它的指針。 沒法將它複製到另外一個unique_ptr, unique_ptr只能移動。 這意味着內存資源的全部權將轉移到新的unique_ptr和原始unique_ptr再也不擁有它。
int* p = new int;
std::unique_ptr<int> ptr(p);
std::unique_ptr<int> ptr1 = ptr; //不能複製,編譯報錯

auto ptr2 = std::move(ptr); //轉移全部權, 如今ptr那塊內存歸ptr2全部, ptr成爲無效的指針.

 

智能指針是個好東西,使用它以後就不用擔憂內存釋放、內存泄露的問題了,個人項目中都是用的智能指針,沒有delete。

智能指針使咱們的程序更安全,除了循環引用會致使內存泄露以外,其餘都很安全,能夠放心使用。

 

c++11 boost技術交流羣:296561497,歡迎你們來交流技術。

相關文章
相關標籤/搜索