C++智能指针详解
来源:互联网 发布:淘宝店铺介绍填写 编辑:程序博客网 时间:2024/06/05 15:06
1.智能指针的产生背景及发展历史:
在C++中动态内存的管理由一对运算符来管理:new,为动态内存分配空间并返回一个指向该对象的指针;delete,接受一个动态对象的指针,并销毁该对象,释放与之相关联的内存。有时我们忘记释放内存,造成内存泄漏;有时在有指针引用内存的情况下就释放了它,在这种情况下会产生引用非法内存的指针。
RAII(一种解决问题的思想):
RAII(Resource Acquisition Is Initialization),也称为为“资源获取就是初始化”,是C++语言的一种管理资源、避免泄漏的惯用法。C++标准保证任何情况下,已构造的对象最终会销毁,即它的析构函数最终会被调用。简单的说,RAII 的做法是使用一个对象,在其构造时获取资源,在对象生命期控制对资源的访问使之始终保持有效,最后在对象析构的时候释放资源。通过应用RAII思想,就产生了智能指针: 智能纸指针的行为类似常规指针;重要的是它负责自动释放所指的对象。
发展历程:
2.模拟实现智能指针
1>模拟实现auto_ptr
template <class T>class AutoPtr {public: AutoPtr(T *ptr) :_ptr(ptr) { } ~AutoPtr() { if (_ptr != NULL) { delete _ptr; _ptr = NULL; } } AutoPtr(AutoPtr <T> & ap) :_ptr(ap._ptr) { ap._ptr = NULL; //只能有一个对象的成员指针指向同一块区域,前一个对象的成员指针置为空指针 } T& operator //注意返回值问题不能返回一个临时变量,临时变量具有常性,会导致不能通过解引用更改值 { return *(this->_ptr); } AutoPtr& operator=(AutoPtr &ap) { //防止自赋值 if (this != &ap) { delete _ptr; this->_ptr = ap._ptr; ap._ptr = NULL; } return *this; } T* operator->() { //this->_ptr->; return _ptr; }private: T *_ptr;};class AA{public: int _a; int _b;};//测试用例void TestAutoPtr(){ AutoPtr<int> ap1(new int); *ap1 = 10; AutoPtr<int> ap2(ap1); //*ap1 = 20; //这句代码会导致程序崩溃,因为当有两个对象的成员指针指向同一块区域 //时,前一个对象的成员指针会被置成空指针 AutoPtr<int> ap3(new int(20)); ap2 = ap3; AutoPtr<AA> ap4(new AA); ap4->_a = 10; ap4->_b = 20; ap2 = ap3;}
2>模拟实现scoped_ptr(和unique_ptr功能类似)
template<class T>class ScopedPtr {public: ScopedPtr(T *ptr) :_ptr(ptr) { } ~ScopedPtr() { if (_ptr) { delete _ptr; _ptr = NULL; } } T& operator *() { return *(_ptr); } T* operator ->() { return _ptr; }protected: //构造和拷贝构造只声明,不定义 ScopedPtr& operator=(const ScopedPtr & sp); ScopedPtr(const ScopedPtr & sp);private: T* _ptr;};class AA{public: int _a; int _b;};//测试用例void TestScopedPtr(){ ScopedPtr<int> ap1(new int); *ap1 = 10; ScopedPtr<int> ap3(new int(10));// ap3 = ap1;// ScopedPtr<int> ap4(ap1);//上述两句代码编译不通过,因为ScopedPtr的构造和拷贝构造只声明,没定义,//且为了防止别人进行修改定义为保护或者私有成员 ScopedPtr<AA> ap2(new AA); ap2->_a = 10; ap2->_b = 20;}
3>shared_ptr的模拟实现(仿函数版)(实际实现要复杂)
仿函数:
仿函数(functor),就是使一个类的使用看上去象一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了。 没有使用仿函数,就不能实现SharedPtr的多种功能,只使用delete删除的话,如果是new[]的空间,就会造成内存泄漏。
template<class T>struct DeleteArray{ void operator()(T *ptr) { delete[] ptr; }};template<class T>struct Delete{ void operator()(T *ptr) { delete ptr; }};struct Fclose{ void operator()(FILE * ptr) { fclose(ptr); }};template<class T,class Del>class SharedPtr {public: SharedPtr(T *ptr) :_ptr(ptr) , _reference_count(new int (1)) { } ~SharedPtr() { Clear(); } void Clear() { if (--(*_reference_count) == 0) { _del(_ptr); delete _reference_count; _reference_count = NULL; } } SharedPtr( SharedPtr<T,Del> & sp) { _ptr = sp._ptr; _reference_count = sp._reference_count; (*_reference_count)++; } //传统写法 //SharedPtr& operator =(const SharedPtr<T,Del> & sp) //{ // if (this != &sp) // { // Clear(); // _ptr = sp._ptr; // _reference_count = sp._reference_count; // (*_reference_count)++; // } // return *this; //} //现代写法 SharedPtr& operator =(SharedPtr<T,Del> sp) { swap(_ptr, sp._ptr); swap(_reference_count, sp._reference_count); return *this; } T& operator *() { return *(this->_ptr); } T* operator->() { return _ptr; }private: T *_ptr; Del _del; int *_reference_count;};//测试用例void TestSharedPtr(){ SharedPtr<int,Delete<int>> ap3(new int(10)); SharedPtr<int,Delete<int>> ap4(ap3); SharedPtr<int,DeleteArray<int>> ap5(new int[10]); SharedPtr<FILE, Fclose>ap6(fopen("text.txt", "w"));}
4>weak_ptr产生原因:
shared_ptr虽然功能强大,但是存在一些问题,比如说循环引用问题。
struct ListNode{ shared_ptr<ListNode> _prev; //shared_ptr为库文件中实现的,只需包memory即可使用 shared_ptr<ListNode> _next; int data; ListNode(int x) { data = x; _prev = NULL; _next = NULL; } ~ListNode() { cout << "~ListNode()" << endl; }};int main() { shared_ptr<ListNode> cur(new ListNode(1)); shared_ptr<ListNode> next(new ListNode(2)); cur->_next = next; next->_prev = cur; return 0; }
循环引用:
为了解决shared_ptr循环引用所带来的问题,就有了weak_ptr:
weak_ptr是一种不控制所指对象生存周期的智能指针,它指向一个shared_ptr所管理的对象。将一个weak_ptr绑定到shared_ptr不会改变shared_ptr的引用计数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放。weak_ptr的名字抓住了这种智能指针“弱”共享对象的特点。
3.智能指针的总结
0 0
- c++ auto_ptr智能指针详解
- C++ 智能指针详解
- C/C++学习笔记:智能指针详解
- C++ 智能指针详解
- C++智能指针详解
- C++智能指针详解
- C++智能指针详解
- C++ 智能指针详解
- C++ 智能指针详解
- C++ 智能指针详解
- 智能指针详解
- C++智能指针详解
- c++ 智能指针详解
- C++智能指针详解
- C++智能指针详解
- C++ 智能指针详解
- C++ 智能指针详解
- C++ 智能指针详解
- NYOJ 260
- 反射
- Kanzi基础---Kanzi基本概念
- 括号匹配 RMQ/暴力
- mysql之简单的多标查询
- C++智能指针详解
- js知识总结
- 【BZOJ】1975 [Sdoi2010]魔法猪学院 k短路(最短路径+A*)
- SSH三大框架的工作原理及流程
- 第一次使用Android Studio时你应该知道的一切配置
- 关系型数据库与非关系型数据库
- LeetCode 435. Non-overlapping Intervals
- Maven知识点扫盲(一)
- 【LeetCode】300. Longest Increasing Subsequence