大家好,欢迎来到IT知识分享网。
C++智能指针
一、智能指针的作用
上一篇介绍了内存池的原理和实现,详情请见内存池设计与实现;
内存池可以帮助我们有效的对内存进行管理,智能指针可以很方便的管理指针,避免出现内存泄漏;
智能指针的作用
智能指针的作用:智能指针可以帮助我们避免在申请空间后忘记释放造成内存泄漏的问题;因为智能指针本身是一个类(后面也会自己实现一下),当出了类的作用域的时候,类会调用析构函数进行释放资源。所以智能指针的作用原理就是在函数结束时自动释放内存空间,不需要手动释放内存空间。
二、智能指针的原理
我们这里的指针指针主要指的是shared_ptr,这也是一种引用计数型智能指针,引用计数顾名思义就是在内存中记录有多少个智能指针被引用,新增一个引用计数加一,过期引用计数则减一,当引用计数为0的时候,
智能指针才会释放资源;
案例一
#include <iostream> #include <memory> using namespace std; class A { public: A() { cout << "A Constructor" << endl; } ~A() { cout << "A Destruct" << endl; } }; int main(){ shared_ptr<A> p = make_shared<A>(); cout << "count:"<<p.use_count() << endl; return 0; }
结果:
root@iZuf67on1pthsuih96udyfZ:~/C++/Net_C++/demo4# ./test1 A Constructor count:1 A Destruct
我们再增加一个传参,看一下引用计数:
案例二
#include <iostream> #include <memory> using namespace std; class A { public: A() { cout << "A Constructor" << endl; } ~A() { cout << "A Destruct" << endl; } }; void fun(shared_ptr<A>p){ cout<<"fun count:"<<p.use_count()<<endl; } int main(){ shared_ptr<A> p = make_shared<A>(); cout << "count:"<<p.use_count() << endl; fun(p); cout << "count:"<<p.use_count() << endl; return 0; }
结果:
root@iZuf67on1pthsuih96udyfZ:~/C++/Net_C++/demo4# ./test1 A Constructor count:1 fun count:2 count:1 A Destruct
通过上面的两个例子,我们验证了最开始说的:智能指针本身是一个类(后面也会自己实现一下),当出了类的作用域的时候,类会调用析构函数进行释放资源;
三、智能指针的使用
智能指针的使用比较简单,在我们程序中需要包含头文件:
#include <memory>
注意:智能指针是C++11 的标准,在编译的时候需要加上 -std=c++11 的编译参数;
使用智能指针初始化有几种方式,new和make_shared,这里推荐使用make_shared,原因是:make_shared标准库函数,是最安全的分配和使用动态内存的方法,此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr;头文件和share_ptr相同。
简单给个案例:
案例三
#include <iostream> #include <memory> using namespace std; class A { public: A(int count) { _nCount = count; } ~A(){} void Print() { cout<<"count:"<<_nCount<<endl; } private: int _nCount; }; int main(){ shared_ptr<A>p = make_shared<A>(10); p->Print(); return 0; }
编译过程;
root@iZuf67on1pthsuih96udyfZ:~/C++/Net_C++/demo4# g++ -std=c++11 test2.cpp -o test2 root@iZuf67on1pthsuih96udyfZ:~/C++/Net_C++/demo4# ./test2 count:10
四、智能指针使用注意项
我们先来看一段代码:
案例四
#include <iostream> #include <memory> using namespace std; class B; class A { public: shared_ptr<B>_pb; }; class B { public: shared_ptr<A>_pa; }; int main(){ shared_ptr<A>pa = make_shared<A>(); shared_ptr<B>pb = make_shared<B>(); cout<<"pa count:"<<pa.use_count()<<endl; cout<<"pb count:"<<pb.use_count()<<endl; pa->_pb = pb; pb->_pa = pa; cout<<"pa count:"<<pa.use_count()<<endl; cout<<"pb count:"<<pb.use_count()<<endl; return 0; }
结果;
root@iZuf67on1pthsuih96udyfZ:~/C++/Net_C++/demo4# g++ -std=c++11 test3.cpp -o test3 root@iZuf67on1pthsuih96udyfZ:~/C++/Net_C++/demo4# ./test3 pa count:1 pb count:1 pa count:2 pb count:2
会发现,最终的引用计数为2,那么结束后,引用计数不为0,他们在堆上的空间不会被释放,这就是常说的循环引用;
当然,这不是无解的,我们可以另外一种只能指针,只不过这是种弱指针—weak_ptr,这种指针不会增加引用计数,配合shared_ptr,可谓是郎才女貌,皆大欢喜呀!
案例五
#include <iostream> #include <memory> using namespace std; class B; class A { public: weak_ptr<B>_pb; }; class B { public: weak_ptr<A>_pa; }; int main(){ shared_ptr<A>pa = make_shared<A>(); shared_ptr<B>pb = make_shared<B>(); cout<<"pa count:"<<pa.use_count()<<endl; cout<<"pb count:"<<pb.use_count()<<endl; pa->_pb = pb; pb->_pa = pa; cout<<"pa count:"<<pa.use_count()<<endl; cout<<"pb count:"<<pb.use_count()<<endl; return 0; }
结果:
root@iZuf67on1pthsuih96udyfZ:~/C++/Net_C++/demo4# g++ -std=c++11 test3.cpp -o test3 root@iZuf67on1pthsuih96udyfZ:~/C++/Net_C++/demo4# ./test3 pa count:1 pb count:1 pa count:1 pb count:1
很清晰的发现,在最后互相引用的时候,引用计数器没有加一,最后出作用域的时候就会调用析构函数,进行内存释放;
五、智能指针的实现
实现智能指针,无论是在面试还是深刻理解智能指针方面,对我们帮助都是非常大的,理解了上面的原理,我们动手实现一个智能指针:
智能指针实现代码
#include <iostream> using namespace std; template<class T> class SmartPoint { public: //构造函数 SmartPoint(T* p=NULL) { _ptr = p; if (p != NULL) { _count = 1; } else { _count = 0; } } //析构函数 ~SmartPoint() { if (--_count == 0) { delete _ptr; } } //拷贝构造函数 SmartPoint(const SmartPoint& src) { if (this != &src) { _ptr = src._ptr; _count = src._count; _count++; } } //重载赋值操作符 SmartPoint& operator=(const SmartPoint& src) { if (_ptr == src._ptr) { return *this; } if (_ptr) { _count--; if (_count == 0) { delete _ptr; } } _ptr = src._ptr; _count = src._count; _count++; return *this; } //重载操作符 T* operator ->() { if (_ptr) return _ptr; } //重载操作符 T& operator *() { if (_ptr) return *_ptr; } size_t use_count() { return _count; } private: T* _ptr; size_t _count; }; void Use(SmartPoint<char> p){ int n = p.use_count(); } int main(){ SmartPoint<char>sp1(new char); Use(sp1); SmartPoint<char>sp2(sp1); SmartPoint<char>sp3; sp3 = sp1; int n = sp1.use_count(); return 0; }
往期精彩文章推荐
- 内存池设计与实现
- 恭喜你!发现宝藏一份–技术文章汇总
- C++11 计时器!真香
- 我们需要懂得CMake文件
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/162013.html