试想一下场景
如下:
这时候只能指针就可以派上用场啦!
RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。
在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:
1.不需要显式地释放资源。
2.采用这种方式,对象所需的资源在其生命期内始终保持有效。
templateclass SmartPtr { public: SmartPtr(T * ptr) :_ptr(ptr)//构造时对想要保护的资源指针进行拷贝 {} ~SmartPtr() { cout << "delete ptr: " << _ptr << endl;//为了看效果 delete _ptr; } //像指针一样使用 T& operator*() { return *_ptr; } T* operator->() { return _ptr; } private: T * _ptr; };
templateC++11更新的智能指针class auto_ptr { public: auto_ptr(T* ptr) :_ptr(ptr) {} auto_ptr(auto_ptr & sp) :_ptr(sp._ptr) { // 管理权转移 sp._ptr = nullptr; } ~auto_ptr() { if (_ptr) { cout << "delete:" << _ptr << endl; delete _ptr; } } // 像指针一样使用 T& operator*() { return *_ptr; } T* operator->() { return _ptr; } private: T* _ptr; };
C++11中的智能指针有以下几种:
unique_ptr:防止拷贝的智能指针 对应boost库中的scoped_ptr
shared_ptr: 可以拷贝的智能指针
weak_ptr: 解决shared_ptr循环引用
template需要拷贝的场景shared_ptr shared_ptr的原理class unique_ptr { public: unique_ptr(T* ptr) :_ptr(ptr) {} ~unique_ptr() { if (_ptr) { cout << "delete:" << _ptr << endl; delete _ptr; } system("pause"); } // 像指针一样使用 T& operator*() { return *_ptr; } T* operator->() { return _ptr; } private: unique_ptr(const unique_ptr &) = delete;//防止拷贝 unique_ptr & operator=(const unique_ptr &) = delete;//防止拷贝 private: T* _ptr;
shared_ptr的原理:是通过引用计数的方式来实现多个shared_ptr对象之间共享资源。
例如:最后一个走的锁门。
1. shared_ptr在其内部,给每个资源都维护了着一份计数,用来记录该份资源被几个对象共享。
2. 在对象被销毁时(也就是析构函数调用),就说明自己不使用该资源了,对象的引用计数减一。
3. 如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源;
4. 如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指针了。
通过下面的程序我们来测试shared_ptr的线程安全问题。需要注意的是shared_ptr的线程安全分为两方面:
1. 智能指针对象中引用计数是多个智能指针对象共享的,两个线程中智能指针的引用计数同时++或–,这个操作不是原子的,引用计数原来是1,++了两次,可能还是2,这样引用计数就错乱了。会导致资源未释放或者程序崩溃的问题。所以只能指针中引用计数++、–是需要加锁的,也就是说引用计数的操作是线程安全的。
2. 智能指针管理的对象存放在堆上,两个线程中同时去访问,会导致线程安全问题。
3. 指向堆上资源的线程安全问题是访问的人处理的,智能指针不管,也管不了.
4. 引用计数的线程安全问题,是智能指针要处理的
总结:智能指针需要锁保证自己的引用计数安全,其访问资源的线程安全智能指针不管是需要操作者自己处理的
先画图介绍shared_ptr如何复制的机制
设计的很有意思可以看看代码品一品:
templateshared_ptr的循环引用问题 如何解决循环引用----->weak_ptrclass shared_ptr { public: shared_ptr(T * ptr) :_ptr(ptr) , _pRefCount(new int (1)) ,_mtx(new mutex) {} void AddRef()//统一接口便于使用 { _mtx->lock(); (*_pRefCount)++; _mtx->unlock(); } void Release()//统一接口便于使用 { bool flag = false; _mtx->lock(); if (--(*_pRefCount) == 0 && _ptr)//引用计数--, 如果引用计数减为0了再释放资源 { cout << "delete:" << _ptr << endl; delete _pRefCount; delete _ptr; flag = true; } _mtx->unlock(); if (flag == true) delete _mtx; } shared_ptr(const shared_ptr & sp)//拷贝构造只需要将引用计数加一 : _ptr(sp._ptr) , _pRefCount(sp._pRefCount) , _mtx(sp._mtx) { AddRef(); } shared_ptr & operator=(const shared_ptr & sp) { if (_ptr != sp._ptr) { Release();//将原来的引用计数-- _ptr = sp._ptr; _pRefCount = sp._pRefCount; _mtx = sp._mtx; AddRef();//将新的引用计数++ } return *this; } ~shared_ptr() { Release(); } T& operator*() { return *_ptr; } T* operator->() { return _ptr; } T* get() const { return _ptr; } int use_count() { return *_pRefCount; } private: T * _ptr; int * _pRefCount;//引用计数 mutex * _mtx; //保护引用计数的锁 };
weak_ptr的特点就是不会增加引用计数,他是专门负责解决shared_ptr的循环引用问题而设计的
template定制删除器class shared_ptr { public: shared_ptr(T * ptr) :_ptr(ptr) , _pRefCount(new int (1)) ,_mtx(new mutex) {} void AddRef()//统一接口便于使用 { _mtx->lock(); (*_pRefCount)++; _mtx->unlock(); } void Release()//统一接口便于使用 { bool flag = false; _mtx->lock(); if (--(*_pRefCount) == 0 && _ptr)//引用计数--, 如果引用计数减为0了再释放资源 { cout << "delete:" << _ptr << endl; delete _pRefCount; delete _ptr; flag = true; } _mtx->unlock(); if (flag == true) delete _mtx; } shared_ptr(const shared_ptr & sp)//拷贝构造只需要将引用计数加一 : _ptr(sp._ptr) , _pRefCount(sp._pRefCount) , _mtx(sp._mtx) { AddRef(); } shared_ptr & operator=(const shared_ptr & sp) { if (_ptr != sp._ptr) { Release();//将原来的引用计数-- _ptr = sp._ptr; _pRefCount = sp._pRefCount; _mtx = sp._mtx; AddRef();//将新的引用计数++ } return *this; } ~shared_ptr() { Release(); } T& operator*() { return *_ptr; } T* operator->() { return _ptr; } T* get() const { return _ptr; } int use_count() { return *_pRefCount; } private: T * _ptr; int * _pRefCount;//引用计数 mutex * _mtx; //保护引用计数的锁 }; template class weak_ptr { public: weak_ptr() :_ptr(nullptr) {} weak_ptr(const shared_ptr & sp) :_ptr(sp.get()) {} weak_ptr & operator=(const shared_ptr & sp) { _ptr = sp.get(); return *this; } T& operator*() { return *_ptr; } T* operator->() { return _ptr; } private: T* _ptr; };
定制删除器 考试基本不考,实际使用有价值
默认情况,智能指针底层都是delete资源
那么如果你的资源不是new出来的呢?比如:new[]、malloc、fopen
定制删除器 – 可调用对象
因为我们默认的是delete,如果new int[]就需要我们设计专门的仿函数来释放资源,否则会造成资源泄露问题。
templateclass default_delete { public: void operator()(const T* ptr) { cout << "delete:" << ptr << endl; delete ptr; } }; template > class unique_ptr { public: unique_ptr(T* ptr) :_ptr(ptr) {} ~unique_ptr() { if (_ptr) { D del; del(_ptr); } system("pause"); } // 像指针一样使用 T& operator*() { return *_ptr; } T* operator->() { return _ptr; } private: unique_ptr(const unique_ptr &) = delete; unique_ptr & operator=(const unique_ptr &) = delete; private: T* _ptr; };
shared_ptr可以在参数列表定制删除器



