1.应用与原理ios
智能指针和普通指针的区别在于智能指针其实是对普通指针加了一层封装机制,这样的一层封装机制的目的是为了使得智能指针能够方便的管理一个对象的生命期。c++经过new和delete来处理动态内存的申请和释放,可是new以后处理很差delete便会致使内存泄漏。可是智能指针的删除是智能指针自己决定的,用户不须要管理释放。c++
智能指针的封装是一个模板,因此使用的方式是shared_ptr<int>,shared_ptr<string>这种格式。ide
2.智能指针的类型函数
[1]shared_ptr,shared_ptr类的本质就是维护了一个引用计数,因此能够有不少shared_ptr同时指向这个内存,每次使用时计数加1,不使用了计数减1,减到0时自动销毁对象。this
#include <iostream> #include <stdio.h> #include <string.h> #include <vector> using namespace std; void fun() { auto tmp = make_shared<int>(6); return ; //离开做用域以后,tmp指向的内存计数减为0,由于自动释放内存 } int main(int argc, char *argv[]) { // shared_ptr的定义 shared_ptr<int> i1; // 空指针 shared_ptr<int> i2 = make_shared<int>(2); //指向一个值为2的int指针,即*i2 是2 auto i3 = make_shared<int>(3); //auto自动设置类型 shared_ptr<string> s1 = "s1"; //shared_ptr的拷贝和赋值 auto i4 = i3; //递增i3指向的int内存引用计数 i3 = i1; //递减i3指向的int内存引用计数,递增i1指向的int内存引用计数 fun(); return 0; }
[2]unique_ptr,这个指针独享一个指向的对象,就是说只能有一个unique_ptr指向一个对象,不能被多个同时指向而已。这个由于不能赋值和拷贝,因此须要用两个函数来处理这些操做:spa
release():调用后会释放全部权,并返回所指向对象的指针。从这里能够看到release只是释放对象的全部权,并无释放对象(而是返回对象的指针),因此必需要接管这个对象指针,不然会形成内存泄漏。指针
s1.release(); //错误,s1指向的内存没有释放,这个内存指针也没法再获取到。正确的应该是s2 = s1.release();code
reset():调用会释放内存(若是unique_ptr不为空),并从新指向一个新的指针。对象
s1.reset(s2.release()); //首先s2释放全部权,返回一个指针,而后s1释放当前指向的内存(若是s1不为空),并接管这个s2返回的指针。blog
s1.reset(); //s1释放当前指向的内存(若是s1不为空),并把s1置空。
这个意思就是release()只是释放全部权,而且须要其余的变量接管这个对象,不接管会内存泄漏。reset就是释放内存,若是有参数,则指向把这个参数指向的对象。
#include <iostream> #include <stdio.h> #include <string.h> #include <vector> using namespace std; int main(int argc, char *argv[]) { // unique_ptr的定义 unique_ptr<int> i1; // 空指针 unique_ptr<int> i2(new int(2)); //指向一个值为2的int指针,即*i2 是2 i1 = i2; //错误,不能被多个指向 // release和reset的使用 unique_ptr<int> s1(new string("s1")); unique_ptr<int> s2(s1.release()); //s1.release() : s1全部权释放后被置空,而后把全部权赋值给s2 unique_ptr<int> s3(new string("s3")); s2.reset(s3.release()); //s3.release() : s3全部权释放后被置空,而后s2当前的全部权被释放,而后把全部权赋值给s2 return 0; }
unique_ptr的例外状况:能够传递unique_ptr参数和返回unique_ptr。这个意思就是说unique_ptr能够当成函数参数传递,由于传参就有拷贝的操做,也能够当成函数的返回值,由于返回一个值,也会有拷贝的操做。可是这两种状况是容许的,例以下面的例子:
unique_ptr<int> fun(int p) { return unique_ptr<int>(new int(p)); }
[3]weak_ptr,是一种不控制所指对象生存期的智能指针,指向一个有shared_ptr管理的对象。将一个weak_ptr绑定到一个shared_ptr不会增长所指对象的引用计数。因此访问weak_ptr时,对象能够已经被删除,所以访问weak_ptr时,须要调用lock()函数,这个lock()函数返回一个指向共享对象的shared_ptr,所以会能够正确使用这个shared_ptr,由于返回shared_ptr会加指向对象的计数。
总结一下就是weak_ptr不保证指向的对象存在,可是能够经过lock()函数随时获取,获取到了就可使用,获取不到(lock()返回空)就说明对象被释放了。参考下面的例子:
shared_ptr<int> i1(new int(10)); weak_ptr<int> i2 = i1; { shared_ptr<int> i3 = i2.lock(); //lock确实是加锁的意思,只不过这里是经过增长i2指向的内存的引用计数(返回一个shared_ptr)来实现加锁 if(i3) printf("weak ptr i2 is valid.\n"); else printf("weak ptr i2 is invalid.\n"); //i3只在此做用域,出了此做用域,i3指向的对象便会减计数,所以会自动解锁 }
3.手动实现一个shared_ptr
这个主要是用到了引用计数的方式。
#include <iostream> #include <stdio.h> #include <string.h> #include <vector> using namespace std; //每一个smart_ptr都有一个ptr和use_count,其中ptr指向共享的对象。use_count指向共享对象的引用计数。 //这个计数固然是须要共享一份。若是各自有各自的计数(例如使用int use_count;),那确定出问题。 template<class T> class smart_ptr { public: smart_ptr(T *p); ~smart_ptr(); smart_ptr(const smart_ptr<T> &orig); smart_ptr<T>& operator=(const smart_ptr<T> &rhs); private: T *ptr; int *use_count; }; // 常规的构造函数 template<class T> smart_ptr<T>::smart_ptr(T *p) : ptr(p) { use_count = new int(1); printf("smart_ptr(T *p) is called!"); } //带参数的构造函数,适应这种初始化smart_ptr<int> p2(p1); template<class T> smart_ptr<T>::smart_ptr(const smart_ptr<T> &orig) { ptr = orig.ptr; use_count = orig.use_count; ++(*use_count); printf("smart_ptr(const smart_ptr<T> &orig) is called!"); } template<class T> smart_ptr<T>::~smart_ptr() { if (--(*use_count) == 0){ delete ptr; delete use_count; ptr = NULL; use_count = NULL; printf("~smart_ptr() is called!"); } } //重载"="操做符:增长右侧计数,减小左侧计数。 template<class T> smart_ptr<T>& smart_ptr<T>::operator=(const smart_ptr<T> &rhs) { ++(*rhs.use_count); if (--(*use_count) == 0){ delete ptr; delete use_count; printf("operator=(const smart_ptr<T> &rhs) is called, delete left side.\n"); } ptr = rhs.ptr; use_count = rhs.use_count; printf("operator=(const smart_ptr<T> &rhs) is called.\n"); return *this; } int main() { smart_ptr<int> p1(new int(0)); p1 = p1; smart_ptr<int> p2(p1); smart_ptr<int> p3(new int(1)); p3 = p1; return 0; }