アドレスポインタオブジェクトストアにアクセスすることにより、CおよびC ++では、それはメモリの動作を指示することができます
が、実用的な技術で、複雑な状況でプログラム予期しないジャンプするので、プログラムがメモリリークが発生する可能性があります。
1 2 3 4 5 6 7 8 9 10 11 12
|
int型 * P = 新しい int型(1);
もし(P) { 返します。}
削除したpを。
|
だから我々は、「スマートポインタ」を導入します
スマートポインタの歴史
スマートポインタは、思考の製品は、(リソース集録された初期化)(リソース割り当て初期化)RAIIです
:として理解することができるスマートポインタ=ポインタ+のRAII。
実際には、ポインタは、ケース上記メモリリークを防ぐために、クラスのコンストラクタとデストラクタ管理ポインタとしてパッケージRAIIへのポインタです。
次のように典型的な例であります
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
テンプレート < クラス > クラス AutoPtr { パブリック: AutoPtr(T *のPTR) :_ptr(PTR) {}
〜AutoPtr() { 場合(_ptr) { 削除 _ptrと、 } }
プライベート: Tの*の_ptr。 }。
|
スマートポインタコードおよび失敗として、少なくとも割り当て動作を実現すべきです。
auto_ptrは
スマートポインタauto_ptrを実装するために最初はC ++ 98で導入された、私たちは「経営権の移転により、RAIIを実現|コピーコンストラクタ、割り当てを実現します。
さauto_ptrをしかし、推奨されていない、直接、新しいモードのデータスタックポインタアドレスのアドレスに転送するには、元のポインタを簡単にプログラムがクラッシュするアクセスしたときに、コピーコンストラクタ、代入、今回のエラーを実現しています。
次のコードを参照します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
テンプレート < クラス > クラス auto_ptrは { パブリック:auto_ptrは(auto_ptrを <T>&A):_ P(a._p) { a._p = NULL ; } auto_ptrは <T>&演算子 =(auto_ptrを <T> A) { _ptr = a._ptr。 a._ptr = NULL ; 返す * これを。 }
プライベート: Tの*の_p。 }
|
これらの欠陥に対応して、ライブラリはscoped_ptrをご紹介ブースト、(ユニークと呼ばれる)もした後に、C ++標準ライブラリが含まれています。
scoped_ptrを
scoped_ptr 通过限制拷贝构造和赋值运算的方式规避 auto_ptr 的缺陷。
具体:不对函数进行定义,使用 private 防止类外实现。
参考代码
1 2 3 4 5 6 7 8 9 10
|
template<class > class auto_ptr { public: private: auto_ptr(auto_ptr<T> &a); auto_ptr<T>& operator= (auto_ptr<T> a); T* _p; }
|
scoped_ptr 终究是一个先天不全的智能指针。
目前的最终版本是 shared_ptr & weak_ptr。
shared_ptr
shared_ptr 是目前使用最广泛的智能指针,随 Boost 引入并在 C++11 被加入标准库
通过「引用计数」 shared_ptr 主要实现如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
|
template<class > class shared_ptr {大专栏 浅析 C++ 智能指针n> public: friend class weak_ptr<T>; shared_ptr(T* ptr = NULL): _ptr(ptr) ,_refCount(int new(1)){}
shared_ptr(const shared_ptr<T> &p): _ptr(p._ptr), _refCount(p._refCount) { (*_refCount)++; }
~shared_ptr() { if (--(*_refCount) == 0) { delete _ptr; delete _refCount; } }
shared_ptr<T>& operator= (const shared_ptr<T> &p) { if (_ptr != p._ptr) { if (--(*_refCount) == 0) { delete _ptr; delete _refCount; } _ptr = p._ptr; _refCount = p._refCount; } } T& operator* (const shared_ptr<T> &p) { return *_ptr; } T* operator-> () { return _ptr; }
private: T* _ptr; int* _refCount;
|
循环引用问题
如下代码运行时,程序会出现无限循环问题,代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
template<class > class shared_ptr { }
typedef shared_ptr<Node> test_ptr; struct Node //链表节点的定义 { dataType data; test_ptr prev; test_ptr next; }
int main(void) { test_ptr p1(new Node); test_ptr p2(new Node); p1 -> next = p2; p2 -> prev = p1; return 0; }
|
如下图所示,在 main 函数结束时,两个智能指针生命周期结束时会依次析构,但在在两者交叉相互指向时,会陷入死循环中:
分析过程容易发现:
main函数执行到末尾时,计数器对 p1, p2 的计数都是2
p2 结束生命周期时,需要先析构 p2-> prev( p1 的空间,计数-1),再析构 p2 本身的空间,计数-1.
p1 结束生命周期时,需要先析构 p1-> next( p2 的空间,计数器将置0,需要 delete p2 )
但delete p2 需要先析构 p2-> prev 即 p1,p1 的析构又需要先析构 p1-> next 即delete p2
故而程序死循环。
循环引用解决方案 —> weak_ptr
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
template<class T> class weak_ptr { public: weak_ptr(T* p = NULL): _ptr(p){}
weak_ptrを(CONST のshared_ptr <T>&P): _ptr(p._ptr){} のweak_ptr <T>&演算子 =(CONST のshared_ptr <T>&P) { _ptr = p._ptr。返す * これを。 } プライベート: Tの*の_ptr。}
|
このとき、shared_ptrのからノード定義における循環参照の問題スマートポインタは、缶をweak_ptrをします。
1 2 3 4 5 6
|
typedefの weak_ptrを<ノード> test_ptr。
|