C++智能指针
2017-12-06 15:59
155 查看
智能指针:存储指向动态分配对象指针的类。
满足的条件:具有RAII思想,能够像指针一样(运算符的重载,解引用,指向对象成员),正确的资源管理。
RAII思想(资源分配及初始化):定义一个类来封装资源的分配和释放,构造函数中完成资源的分配和初始化,析构函数中完成资源的清理,可以保证资源的正确初始化和释放。
引入智能指针的目的是什么呢?
这里给出一段代码:
上述代码在func函数中new一个四字节空间并进行初始化,接下来if条件判断语句为真,抛出异常,main函数直接捕获异常,函数返回0,导致开辟的空间没有被释放,造成内存泄漏。
其实只要在throw之前加一个delete语句就可以解决问题,但是重点是当代码超级多的时候,肯定会忘记的。那么有没有一种方法是可靠的呢——”智能指针“。
智能指针的发展历史
C++98 : auto_ptr 在构造对象的时候获取对象的管理权(管理权转移),
带有缺陷。“不提倡使用”
boost库(非官方):scoped_ptr 防拷贝的守卫指针(简单粗暴)。—scoped_array
shared_ptr 加入引用计数的共享指针(复杂,有循环引用的缺陷)。—shared_array
weak_ptr 不能单独存在的弱指针(辅助解决shared_ptr循环引用的问题)
C++11 (官方库):沿用了boost库,将scoped_ptr改名为unique_ptr,shared_ptr和weak_ptr名字没变。
详解auto_ptr:
auto_ptr事实上是一个类,在构造时获取对象的管理权,不用考虑啥时候释放动态开辟的空间,在析构函数中直接释放,不会出现内存泄露的问题。
缺陷:
1.一个指针变量指向的空间不能由两个auto_ptr管理,不然会析构两次,程序崩溃;
2.auto_ptr不能用来管理数组,析构函数中用的是delete。
详解scoped_ptr
scoped_ptr防拷贝(拷贝构造函数和赋值运算符的重载是只声明不实现;用private对其进行访问限定,防止在类外定义)直接明了。
缺陷:不能拷贝,管理的对象不能共享所有权,功能不全面。
scoped_array
scoped_array和scoped_ptr的功能是一样的,只是scoped_array管理的是数组,需要像数组一样。
详解shared_ptr
Shared_ptr会出现循环引用:
![](https://img-blog.csdn.net/20171206134149444?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyOTU3NTU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20171206133053801?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyOTU3NTU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
为什么每个节点都有两个引用计数呢?这就是循环引用的问题。
为了解决循环引用问题,这里需引入weak_ptr.
详解weak_ptr
weak_ptr是和shared_ptr配合使用的,weak_ptr不增加节点的引用计数。
那么weak_ptr是如何解决循环引用问题?
满足的条件:具有RAII思想,能够像指针一样(运算符的重载,解引用,指向对象成员),正确的资源管理。
RAII思想(资源分配及初始化):定义一个类来封装资源的分配和释放,构造函数中完成资源的分配和初始化,析构函数中完成资源的清理,可以保证资源的正确初始化和释放。
引入智能指针的目的是什么呢?
这里给出一段代码:
void func() { int *_ptr = new int(3); if (_ptr) { throw 3; } delete _ptr; } int main() { try { func(); } catch (...) {} return 0; }
上述代码在func函数中new一个四字节空间并进行初始化,接下来if条件判断语句为真,抛出异常,main函数直接捕获异常,函数返回0,导致开辟的空间没有被释放,造成内存泄漏。
其实只要在throw之前加一个delete语句就可以解决问题,但是重点是当代码超级多的时候,肯定会忘记的。那么有没有一种方法是可靠的呢——”智能指针“。
智能指针的发展历史
C++98 : auto_ptr 在构造对象的时候获取对象的管理权(管理权转移),
带有缺陷。“不提倡使用”
boost库(非官方):scoped_ptr 防拷贝的守卫指针(简单粗暴)。—scoped_array
shared_ptr 加入引用计数的共享指针(复杂,有循环引用的缺陷)。—shared_array
weak_ptr 不能单独存在的弱指针(辅助解决shared_ptr循环引用的问题)
C++11 (官方库):沿用了boost库,将scoped_ptr改名为unique_ptr,shared_ptr和weak_ptr名字没变。
详解auto_ptr:
auto_ptr事实上是一个类,在构造时获取对象的管理权,不用考虑啥时候释放动态开辟的空间,在析构函数中直接释放,不会出现内存泄露的问题。
//auto_ptr的模拟实现 template <class T> class Auto_ptr { public: Auto_ptr(T* ptr)//构造函数 :_ptr(ptr) {} Auto_ptr(Auto_ptr<T>& ap)//拷贝构造函数 : _ptr(ap._ptr) { ap._ptr = NULL; } Auto_ptr<T>& operator=(Auto_ptr<T>& ap)//赋值运算符的重载 { if (this != &ap) { if (_ptr) { delete _ptr; } _ptr = ap._ptr; 4000 ap._ptr = NULL; } return *this; } ~Auto_ptr()//析构函数 { if (_ptr) { delete _ptr; } } T& operator*() { return *_ptr; } T* operator->() { return _ptr; } private: T* _ptr; }; struct AA { int _a; int _b; }; int main() { Auto_ptr<int> ap(new int (3)); *ap = 5; Auto_ptr<int> ap1(ap); Auto_ptr<int> ap3(ap);//一个auto_ptr被拷贝或被赋值后, 其已经失去对原对象的所有权指向NULL Auto_ptr<AA> ap2(new AA); ap2->_a = 2; ap2->_b = 3; return 0; }
缺陷:
1.一个指针变量指向的空间不能由两个auto_ptr管理,不然会析构两次,程序崩溃;
//错误 int *ptr=new int(5); auto_ptr<int> ap(ptr); auto_ptr<int> ap(ptr);
2.auto_ptr不能用来管理数组,析构函数中用的是delete。
int *ptr=new int[6]; auto_ptr<int> ap(ptr);
详解scoped_ptr
scoped_ptr防拷贝(拷贝构造函数和赋值运算符的重载是只声明不实现;用private对其进行访问限定,防止在类外定义)直接明了。
//scoped_ptr的模拟实现 template <class T> class Scoped_ptr { public: Scoped_ptr(T* ptr) :_ptr(ptr) {} ~Scoped_ptr() { if (_ptr) { delete _ptr; } } T& operator*() { return *_ptr; } T* operator->() { return _ptr; } private: Scoped_ptr(const Scoped_ptr<T>& sp); Scoped_ptr<T>& operator=(const Scoped_ptr<T>& sp); T* _ptr; }; int main() { Scoped_ptr<int> sp(new int(2)); return 0; }
缺陷:不能拷贝,管理的对象不能共享所有权,功能不全面。
scoped_array
scoped_array和scoped_ptr的功能是一样的,只是scoped_array管理的是数组,需要像数组一样。
//scoped_array的模拟实现 template <class T> class Scoped_array { public: Scoped_array(T* ptr) :_ptr(ptr) {} ~Scoped_array() { if (_ptr) { delete[] _ptr; } } T& opeartor[](size_t i) { return _ptr[i]; } private: Scoped_array(const Scoped_array<T>& sa); Scoped_array<T>& operator=(const Scoped_array& sa); T* _ptr; }; int main() { Scoped_array<int> sa(new int[3]); return 0; }
详解shared_ptr
//shared_ptr模拟实现 template <class T> class Shared_ptr { public: Shared_ptr(T* ptr == NULL) :_ptr(ptr) , _refCount(new int(1)) {} Shared_ptr(const Shared_ptr<T>&sp) :_ptr(sp._ptr) ,_refCount(sp._refCount) { *_refCount++; } Shared_ptr<T>&operator=(const Shared_ptr<T>& sp) { if (_ptr != &sp._ptr) { if (--(*_refCount) == 0) { delete _ptr; delete _refCount; } _ptr = sp._ptr; _refCount = sp._refCount; (*_refCount)++; } return *this; } ~Shared_ptr() { if (--(*_refCount) == 0) { delete _ptr; delete _refCount; } } T& operator*() { return *_ptr; } T* opeartor->() { return _ptr; } int Count() { return *_refCount; } private: T* _ptr; int *_refCount; };
Shared_ptr会出现循环引用:
//测试代码 struct ListNode { int _data; Shared_ptr<ListNode> _next; Shared_ptr<ListNode> _prev; ListNode(int x) :_data(x) , _next(NULL) , _prev(NULL) {} ~ListNode() {} }; int main() { Shared_ptr<ListNode> cur(new ListNode(1)); Shared_ptr<ListNode> next(new ListNode(2)); cur->_next = next; next->_prev = cur; cout << "cur._refCount " <<cur.Count()<<endl; cout << "next._refCount "<<cur.Count()<<endl; system("pause"); }
为什么每个节点都有两个引用计数呢?这就是循环引用的问题。
为了解决循环引用问题,这里需引入weak_ptr.
详解weak_ptr
weak_ptr是和shared_ptr配合使用的,weak_ptr不增加节点的引用计数。
//weak_ptr的模拟实现 template <class T> class Weak_ptr { public: Weak_ptr() :_ptr(NULL) {} Weak_ptr(const Shared_ptr<T>& sp) :_ptr(sp._ptr) {} Weak_ptr<T>& operator=(const Shared_ptr<T>& sp) { _ptr = sp._ptr; return *this; } ~Weak_ptr() { if (_ptr) { delete _ptr; } } T& operator*() { return *this; } T* operator->() { return _ptr; } private: T* _ptr; };
那么weak_ptr是如何解决循环引用问题?
struct ListNode { int _data; Weak_ptr<ListNode> _next; Weak_ptr<ListNode> _prev; ListNode(int x) :_data(x) , _next() , _prev() {} ~ListNode() {} }; int main() { Shared_ptr<ListNode> cur(new ListNode(3)); Shared_ptr<ListNode> next(new ListNode(4)); cur->_next = next; next->_prev = cur; cout << "cur._refCount " << cur.Count() << endl; cout << "next._refCount "<<cur.Count()<<endl; system("pause"); }
相关文章推荐
- C++——智能指针
- C++ 智能指针
- C++实现智能指针(shared_ptr和unique_ptr)与删除器
- 【C++】浅谈boost库智能指针
- C++文本查询程序 不要定义类和智能指针管理数据 C++Primer练习12.28 使用vector,map,set容器保存来自文件的数据并生成查询结果
- C++ 智能指针
- C++ 智能指针
- C++智能指针
- C++ 智能指针
- c++之我们为什么选择使用智能指针
- C++ 什么是智能指针?
- C++ 智能指针
- C++学习笔记(八) 智能指针
- C++文本查询程序 不要定义类和智能指针管理数据 C++Primer练习12.28 使用vector,map,set容器保存来自文件的数据并生成查询结果
- 必须要注意的 C++ 动态内存资源管理(五)——智能指针陷阱
- C++中的动态内存与智能指针
- C++ 智能指针
- 异常处理与MiniDump详解(2) 智能指针与C++异常
- C++智能指针
- 【C++】Vs2008中使用智能指针