一、智能指针的作用
智能指针的作用
智能指针的作用 :智能指针可以帮助我们避免在申请空间后忘记释放造成内存泄漏的问题;因为智能指针本身是一个类(后面也会自己实现一下),当出了类的作用域的时候,类会调用析构函数进行释放资源。所以智能指针的作用原理就是在函数结束时自动释放内存空间,不需要手动释放内存空间。
二、智能指针的原理
我们这里的指针指针主要指的是 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; }
送大家一张后台开发相关面试知识点汇总脑图 这是片段:
大家可以加qun获取。