內存垃圾管理(智能指針)


智能指針 shared_ptr:
https://blog.csdn.net/u012501459/article/details/48229399

C++11中引入了智能指針的概念。使用普通指針,容易造成堆內存泄露(忘記釋放),二次釋放,使用智能指針能更好的管理堆內存。

  • 構造函數中創建類的新對象時,初始化引用計數爲1;
  • 拷貝構造函數複製指針,並使相應的引用計數增加1;
  • 賦值操作減少左操作數所值對象的引用計數,增加右操作數所指對象的引用計數;
  • 析構函數使引用計數減少1,並且當引用計數爲0時,釋放指針說指向的對象;


定製刪除器:

#include<iostream>
#include<memory>
using namespace std;
int main(){
    shared_ptr<int> sp1(new int(10));
    cout<<*sp1<<endl;
    *sp1 = 20;
    cout<<*sp1<<endl;
        return 0;
}

我們動態申請的內存,構造時完成初始化,析構時通過delete來釋放沒有任何問題。但是文件指針可能就掛了。

#include<iostream>
#include<memory>
using namespace std;
int main(){
    shared_ptr<FILE> sp1(fopen("test.txt","w"));
    //如果不進行任何特殊處理,則程序崩潰!
    return 0;
}

因此,shared_ptr提供了刪除器功能,我們可以通過定製刪除器,來對特定的資源進行回收。

#include<iostream>
#include<memory>
using namespace std;
 
//仿函數
struct Fclose{
    void operator()(void *ptr){
        fclose((FILE*)ptr);
        cout<<"不用擔心,shared_ptr已經通過調用我關閉了文件!"<<endl;
    }
};
 
int main(){
    //我們通過傳入仿函數,來完成對文件指針的清理
    shared_ptr<FILE> sp1(fopen("test.txt","w"),Fclose());
    return 0;
}

Ref_ptr類:

//使用int*指針初始化ptr,注意必須要放在初始化列表中
Ref_ptr(int * i):ptr(new Referenced(i))
{

}
//拷貝構造函數,又有一個變量指向了這塊內存
Ref_ptr(const Ref_ptr & rhs)
{
    ptr=rhs.ptr;//將右操作數的引用計數對象賦值給左操作數
    ptr->ref();//將它們的應用計數加1
}

Ref_ptr r1=new int(4); //調用構造函數
Ref_ptr r2=r1; //調用拷貝構造函數
//賦值操作符,右操作數的引用計數要減1,左操作數的引用計數要加1
Ref_ptr & operator=(const Ref_ptr & rhs)
{
    if(&rhs==this)
        return *this;
    if(ptr->unref()==0)//賦值操作符,首先將當前類的引用計數減1,因爲現在指向它的指針少了一個。
    {
        cout<<"delete Ref_ptr"<<endl;
        delete ptr;
    }
    ptr=rhs.ptr; //將右操作數的引用計數賦值給當前對象
    ptr->ref(); //引用計數加1
    return *this;
}

//析構函數,引用計數要減1,如果減爲0,刪除這塊內存
~Ref_ptr()
{
    if(ptr->unref()==0)
    {
        cout<<"delete Ref_ptr"<<endl;
        delete ptr;
    }
}

Referenced類:

//初始化這個類,引用計數設爲1,並且將p指向傳入的地址
Referenced(int * pi)
{
    refCount=1;
    p=pi;
}

//引用計數加1
int ref()
{
    return ++refCount;
}   

//引用計數減1
int unref()
{
    return --refCount;
}

//析構函數,釋放掉內存
~Referenced()
{
    cout<<"delete referenced"<<endl;
    delete p;
}

好處:

  • 智能指針能夠幫助我們處理資源泄露問題;
  • 它也能夠幫我們處理空懸指針的問題;
  • 它還能夠幫我們處理比較隱晦的由異常造成的資源泄露。

循環引用:

#include <memory>
class B;
class A
{
public:
    ~A()
    {
        printf("delete A");
    }
    std::shared_ptr < B >
        m_b;
};
 
class B
{
public:
    ~B()
    {
        printf("delete B");
    }
    std::shared_ptr < A >
        m_a;
};
 
int main()
{
    std::shared_ptr<A> a(new A); //new出來的A的引用計數此時爲1
    std::shared_ptr<B> b(new B); //new出來的B的引用計數此時爲1
    a->m_b = b; //B的引用計數增加爲2
    b->m_a = a; //A的引用計數增加爲2
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章