一、什么是智能指针
在使用堆内存时,就像使用栈内存空间一样,可以实现自释放的功能,智能指针在C++库中也是类模板之一。
二、智能指针有几种
有四种。auto_ptr, unique_ptr, shared_ptr, weak_ptr 其中后三个是C++11支持,第一个已经被C++弃用且被unique_ptr 代替,不推荐使用。
1、unique_ptr, 实现了独占式拥有的概念,同一个时间只能有一个智能指针可以指向该对象,因为无法进行拷贝构造和拷贝赋值,但是可以进行移动构造和移动赋值。
2、share_ptr, 实现了共享式拥有的概念,即多个智能指针可以指向相同的对象,该对象及相关资源会在其所指对象不再使用之后,自己释放与对象相关的资源。
3、weak_ptr, 解决share_ptr相互引用时,两个指针的引用计数永远不会下降为0,从而导致死锁问题。而weak_ptr 是对对象的一种弱引用,可以绑定share_ptr, 但不会增加对象的引用计数。
4、atuo_ptr, 实现独占式拥有的概念,同一时间只能有一个智能指针可以指向该对象;但atuo_ptr在C++17中被摒弃,其主要问题在于:对象所有权的转移,比如在函数传参过程中,对象所有权不会返还,从而存在潜在的内存崩溃问题;不能指向数组,也不能作为STL容器的成员。
三、智能指针的特点
1、在C++库中也是类模板之一。
2、实际上将指针封装在一个类,通过对象来管理指针。
3、作用主要用来管理内存,在C++中,是一种管理资源,避免泄漏内存的习惯用法,也称RAII(资源获取及初始化)
四、案例
1、auto_ptr的简单实现
#include <iostream> using namespace std; class Test1 { private: int a; public: Test1(int a = 0) { cout << "Test1()" << endl; this->a = a; } ~Test1() { cout << "~Test1()" << endl; } void show() { cout << "a = " << a << endl; } }; class Test2 { private: int a; public: Test2(int a = 0) { cout << "Test2()" << endl; this->a = a; } ~Test2() { cout << "~Test2()" << endl; } void show() { cout << "a = " << a << endl; } }; template <class T> class myauto_ptr { private: T *ptr; public: // 使用类模板的方式来适应多个类 myauto_ptr(T *ptr = T ()) { this->ptr = ptr; } ~myauto_ptr() { delete ptr; // 重点在这里 cout << "~myauto_ptr" << endl; } // 重载成员函数, 让本类的指针成员变量可以调用T类对象的成员函数 T* operator ->() { return ptr; } T& operator *() { return *ptr; } }; int main() { Test1 *p1 = new Test1(10); // delete p1; // 如果没有这步,会造成内存泄漏 Test2 *p2 = new Test2(20); myauto_ptr<Test1> p3(new Test1(100)); myauto_ptr<Test2> p4(new Test2(200)); p3->show(); (*p4).show(); return 0; }
2、share_ptr的简单实现
#include <iostream> using namespace std; // 定义一个共享的全局变量,用来描述指向某个对象的指针个数 int share_count = 1; class Test1 { private: int a; public: Test1(int a = 0) { cout << "Test1()" << endl; this->a = a; } ~Test1() { cout << "~Test1()" << endl; } void show() { cout << "a = " << a << endl; } }; template <class T> class myshare_ptr { private: T *ptr; public: // 使用类模板的方式来适应多个类 myshare_ptr(T *ptr = T ()) { this->ptr = ptr; } ~myshare_ptr() { cout << "count :" << share_count-1 << endl; if(this->ptr != nullptr && --share_count == 0) { delete ptr; // 重点在这里 } cout << "~myshare_ptr" << endl; } myshare_ptr(const myshare_ptr& other) { this->ptr = other.ptr; share_count++; } T& operator = (const myshare_ptr& other) { share_count++; this->ptr = other.ptr; return *this->ptr; } // 重载成员函数, 让本类的指针成员变量可以调用T类对象的成员函数 T* operator ->() { return ptr; } T& operator *() { return *ptr; } }; int main() { Test1 *p1 = new Test1(10); // delete p1; // 如果没有这步,会造成内存泄漏 myshare_ptr<Test1> p2(new Test1(100)); myshare_ptr<Test1> p3 = p2; myshare_ptr<Test1> p4 = p2; p3->show(); return 0; }
五、总结
本篇只是简单讲解一下四种智能指针,并简单实现了两个简单的案例,实际使用中还是用C++提供的智能指针。了解内部原理有助于正确使用。