上一篇介绍了内存池的原理和实现,详情请见内存池设计与实现;ios
内存池能够帮助咱们有效的对内存进行管理,智能指针能够很方便的管理指针,避免出现内存泄漏;c++
智能指针的做用面试
智能指针的做用:智能指针能够帮助咱们避免在申请空间后忘记释放形成内存泄漏的问题;由于智能指针自己是一个类(后面也会本身实现一下),当出了类的做用域的时候,类会调用析构函数进行释放资源。因此智能指针的做用原理就是在函数结束时自动释放内存空间,不须要手动释放内存空间。安全
咱们这里的指针指针主要指的是shared_ptr
,这也是一种引用计数型智能指针,引用计数顾名思义就是在内存中记录有多少个智能指针被引用,新增一个引用计数加一,过时引用计数则减一,当引用计数为0的时候,bash
智能指针才会释放资源;服务器
案例一微信
#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
复制代码
咱们再增长一个传参,看一下引用计数:学习
案例二ui
#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++后台服务器方面的知识,请关注: 微信公众号:====**CPP后台服务器开发**
====
本文使用 mdnice 排版