智能指針

指針的危害

  • 指針未初始化
  • 野指針
  • 內(nèi)存泄漏

參考閱讀C/C++指針使用常見的坑

智能指針分類

智能指針 進入C++標準的版本 STL頭文件 boost頭文件 說明
auto_ptr C++03 <memory> <boost/auto_ptr.hpp> 盡量避免使用
unique_ptr C++11 <memory> <boost/unique_ptr.hpp> 管理單個堆內(nèi)存對象,獨享所有權(quán),不允許賦值和拷貝,不能用于管理數(shù)組對象
shared_ptr C++11 <memory> <boost/shared_ptr.hpp> 引用計數(shù)智能指針,共享所有權(quán)
weak_ptr C++11 <memory> <boost/weak_ptr.hpp> shared_ptr的觀察者,只進行引用而不改變引用計數(shù),用來解決shared_ptr的循環(huán)引用問題
scoped_ptr - - <boost/scoped_ptr.hpp> 作用域智能指針,功能與unique_ptr相似。
  • 本質(zhì):
    將指針封裝為類對象成員,并在析構(gòu)函數(shù)里刪除指針指向的內(nèi)存。
  • 不同:
    • auto_ptr、unique_ptrscoped_ptr馬上刪除。
    • shared_ptr計數(shù)為0刪除。
    • weak_ptr不刪除。

智能指針是來解決指針危害的。


1. auto_ptr

  • 作用
    對作用域內(nèi)的動態(tài)分配對象的自動釋放
  • 基本類型
#include <iostream>
#include <memory>
using namespace std;
int main(){
    int* pn = new int(10);
    auto_ptr<int> ap(pn);
    cout << *ap << endl;
}
  • 類類型
#include <iostream>
#include <memory>
using namespace std;
class Test{
public:
    Test(){cout << __func__ << endl;}
    ~Test(){cout << __func__ << endl;}
    void Func(){cout << __func__ << endl;}
};
int main(){
    Test* pt = new Test;
    auto_ptr<Test> apt(pt);
    apt->Func();
}

通過valgrind可以看到?jīng)]有內(nèi)存泄露,指針可以被正常釋放。

  • 缺陷
  1. 兩個auto_ptr不能同時擁有同一個對象
#include <memory>
using namespace std;
int main(){
    int* pn = new int(10);
    auto_ptr<int> ap1(pn);
    auto_ptr<int> ap2(pn);
}
  1. auto_ptr不能管理數(shù)組指針
#include <memory>
using namespace std;
int main(){
    int*pa=new int[10];
    auto_ptr<int>ap(pa);
}
  1. auto_ptr被拷貝或被賦值后,失去對原指針的管理.這種情況被稱為指針所有權(quán)傳遞。

賦值的情況

#include <iostream>
#include <memory>
using namespace std;
int main(){
    int*p = new int(10);
    auto_ptr<int> ap1(p);
    cout<< *ap1 <<endl;
    auto_ptr<int> ap2=ap1;
    cout<< *ap1 <<endl;
}

拷貝的情況

#include <iostream>
#include <memory>
using namespace std;
void Func(auto_ptr<int> ap){
    cout << *ap << endl;
}
int main(){
    int*p = new int(10);
    auto_ptr<int> ap(p);
    cout<< *ap <<endl;
    Func(ap);
    cout<< *ap <<endl;
}
  1. auto_ptr不能作為容器對象,因為STL容器中的元素經(jīng)常要支持拷貝,賦值等操作。
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
int main(){
    int*p = new int(10);
    auto_ptr<int> ap(p);
    vector<auto_ptr<int> > vec;
    vec.push_back(ap);
}

2. unique_ptr

  • 作用
    代替auto_ptr,不復制與賦值。

3. scoped_ptr

  • 作用
    unique_ptr相似,在本作用域中使用,不能復制與賦值。

4. shared_ptr

循環(huán)引用問題

#include <string>  
#include <iostream>  
#include <boost/shared_ptr.hpp>  
#include <boost/weak_ptr.hpp>  
  
class parent;  
class children;  
  
class parent {  
public:  
    ~parent() { std::cout <<"destroying parent\n"; }  
public:  
    boost::shared_ptr<children> children;  
};  
  
class children {  
public:  
    ~children() { std::cout <<"destroying children\n"; }  
public:  
    boost::shared_ptr<parent> parent;  
};  
void test(){  
    boost::shared_ptr<parent> father(new parent());  
    boost::shared_ptr<children> son(new children);  
    father->children = son;  
    son->parent = father;  
}  
void main(){  
    std::cout<<"begin test...\n";  
    test();  
    std::cout<<"end test.\n";  
}  

5. weak_ptr

解決shared_ptr循環(huán)引用問題

#include <string>  
#include <iostream>  
#include <boost/shared_ptr.hpp>  
#include <boost/weak_ptr.hpp>  

using namespace boost; 

class parent;  
class children;  
class parent {  
public:  
    ~parent() { std::cout <<"destroying parent\n"; }  
public:  
    shared_ptr<children> children;  
};
class children {  
public:  
    ~children() { std::cout <<"destroying children\n"; }
public:  
    weak_ptr<parent> parent;  
};
void test(){  
    shared_ptr<parent> father(new parent());  
    shared_ptr<children> son(new children);  
    father->children = son;  
    son->parent = father;  
}
void main(){  
    std::cout<<"begin test...\n";  
    test();  
    std::cout<<"end test.\n";  
}  

智能指針weak_ptr主要用來協(xié)助shared_ptr。不參與引用計數(shù),但是有以下好處:
1 打破遞歸的依賴關系
2 使用一個共享的資源但是不要所有權(quán),不添加引用計數(shù)
3 避免懸空指針。

  • 方法一
    boost::shared_ptr<std::string> sp(new std::string("method1");
    // 從shared_ptr構(gòu)建出來
    boost::weak_ptr<std::string>wp(sp);
    // 再從shared_ptr獲取回去
    boost::shared_ptr<std::string> p = wp.lock();
    
  • 方法二
    // 方法二
    boost::shared_ptr<std::string> sp(new std::string("method1");
    // 從shared_ptr構(gòu)建出來
    boost::weak_ptr<std::string>wp(sp);
    // 再從shared_ptr獲取回去
    boost::shared_ptr<std::string> p(wp);
    

總結(jié)

智能指針的特性

智能指針 管理同一個對象 可拷貝 可復制 所有權(quán) 成為容器元素 管理數(shù)組指針
auto_ptr NG OK OK 傳遞 NG NG
unique_ptr NG NG NG 獨享 NG NG
scoped_ptr NG NG NG 獨享 NG NG
shared_ptr NG OK OK 共享 OK NG
weak_ptr NG OK OK 共享 OK NG

雖然通過弱引用指針可以有效的解除循環(huán)引用,但這種方式必須在程序員能預見會出現(xiàn)循環(huán)引用的情況下才能使用,也可以是說這個僅僅是一種編譯期的解決方案。
如果程序在運行過程中出現(xiàn)了循環(huán)引用,還是會造成內(nèi)存泄漏的。
因此,不要認為只要使用了智能指針便能杜絕內(nèi)存泄漏。

C++:Boost庫_weak_ptr

內(nèi)存管理技術

實踐

有關智能指針的使用規(guī)則

  • Effective C++
    條款17:以獨立語句將newed對象置于智能指針
  • Effective STL
    條款8:永不建立auto_ptr的容器
  • Exceptional C++
    條款37:auto_ptr
  • More Exceptional C++
    條款21:未管理指針存在的問題,之二:使用 auto_ptr?
    條款29:使用 auto_ptr
    條款30:智能指針成員,之一:auto_ptr 存在的問題
  • Effective Modern C++
    條款18: 使用std::unique_ptr來管理獨占所有權(quán)的資源
    條款19: 使用std::shared_ptr來管理共享所有權(quán)的資源
    條款20: 使用std::weak_ptr替換會造成指針懸掛的類std::shared_ptr指針
    條款21: 比起直接使用new優(yōu)先使用std::make_uniquestd::make_shared

簡單實現(xiàn)智能指針

// #include <memory>
#include <iostream>
using namespace std;

// auto_ptr C++03 C++11以后被廢棄
// unique_ptr C++11 ~ scope_ptr boost 
// shared_ptr C++11/boost
// weak_ptr C++11/boost

namespace miniSTL{
template<typename T>
class auto_ptr{
public:
    typedef T value_type;
    typedef value_type* pointer;
    typedef value_type& reference;
    typedef const reference const_reference;
private:
    pointer ptr;
public:
    auto_ptr(pointer p):ptr(p){}
    auto_ptr(const auto_ptr& p):ptr(p.ptr){
       const_cast<auto_ptr&>(p).ptr = NULL; // 
    }
    auto_ptr& operator=(const auto_ptr& p){
        if(this == &p) return *this;
        delete ptr;
        ptr = p.ptr;
        const_cast<auto_ptr&>(p).ptr = NULL; // 
    }
    ~auto_ptr(){delete ptr;}
    reference operator*(){return *ptr;} 
    const_reference operator*()const{return *ptr;} 
    pointer operator->(){return ptr;}
    const pointer operator->()const{return ptr;}
};

template<typename T>
class unique_ptr{
public:
    typedef T value_type;
    typedef value_type* pointer;
    typedef value_type& reference;
    typedef const reference const_reference;
private:
    pointer ptr;
public:
    unique_ptr(pointer p):ptr(p){}
    unique_ptr(const unique_ptr& p) = delete;
    unique_ptr& operator=(const unique_ptr& p) = delete;
    ~unique_ptr(){delete ptr;}
    reference operator*(){return *ptr;} 
    const_reference operator*()const{return *ptr;} 
    pointer operator->(){return ptr;}
    const pointer operator->()const{return ptr;}
};
};

using namespace miniSTL;

void Func(auto_ptr<int> ap){
    cout << *ap << endl;
}
void Func(unique_ptr<int> up){
    cout << *up << endl;
}
void Func(shared_ptr<int> sp){
    cout << *sp << endl;
}

class IntegerPtr{
    shared_ptr<int> ptr;
public:
    IntegerPtr(int n):ptr(new int(n)){}
    void Print(){
        cout << *ptr << endl;
    }
};

int main(){
    auto_ptr<int> ap(new int(100));
//    Func(ap);
//    auto_ptr<int> ap2 = ap;
    cout << *ap << endl;

    unique_ptr<int> up(new int(100));
    // Func(up);
    // unique_ptr<int> up2 = up;
    cout << *up << endl;
    
    shared_ptr<int> sp(new int(110));
    Func(sp);
    shared_ptr<int> sp2 = sp;
    cout << *sp2 << endl;
    cout << *sp << endl;

    // 空指針解引用
    // int* p = NULL;
    // cout << *p << endl;
    IntegerPtr ptr(200);
    ptr.Print();
    IntegerPtr ptr2 = ptr;
    ptr2.Print();
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • C++ 智能指針詳解 一、簡介由于 C++ 語言沒有自動內(nèi)存回收機制,程序員每次 new 出來的內(nèi)存都要手動 de...
    yangqi916閱讀 1,451評論 0 2
  • 1. 什么是智能指針? 智能指針是行為類似于指針的類對象,但這種對象還有其他功能。 2. 為什么設計智能指針? 引...
    MinoyJet閱讀 707評論 0 1
  • 導讀## 最近在補看《C++ Primer Plus》第六版,這的確是本好書,其中關于智能指針的章節(jié)解析的非常清晰...
    小敏紙閱讀 2,085評論 1 12
  • C++智能指針 原文鏈接:http://blog.csdn.net/xiaohu2022/article/deta...
    小白將閱讀 6,994評論 2 21
  • 原作者:Babu_Abdulsalam 本文翻譯自CodeProject,轉(zhuǎn)載請注明出處。 引入### Ooops...
    卡巴拉的樹閱讀 30,362評論 13 74

友情鏈接更多精彩內(nèi)容