C++中,动态内存的管理是通过new和delete一对运算符进行管理的。在代码编辑过程中,正确的释放内存空间往往复杂而困难。因此,为了更加安全的管理内存,C++11添加了智能指针。
想要使用智能指针,要先包含头文件< memory >
一,shared_ptr类
智能指针也是模板,因此在创建一个智能指针的时候要提供指针指向的类型
shared_ptr<int> p1;
shared_ptr<string>p2;
make_shared函数
在分配动态内存时,最安全的方法就是调用make_shared()函数,这个函数可以在动态内存中分配一个对象进行初始化并返回指向此对象的shared_ptr
shared_ptr<int> p3=make_shared<int>(1234);
在日常使用中,我们也可以使用auto类型的对象来保存make_shared()的结果
auto p4=make_share<string>("Hello World");
其他初始化方法
除了make_shared函数对shared_ptr对象进行初始化以外,还可以使用构造函数和拷贝构造函数对其进行初始化。
//调用构造函数进行初始化
shared_ptr<int>p4(new int(222));
//调用拷贝构造进行初始化
shared_ptr<int>p5(p4);
在使用构造函数初始化指针时要注意,智能指针的构造函数是使用explicit进行修饰的,因此不接受隐式转换
shared_ptr<int> p6=new int(1024);//会报错
shared_ptr内存管理
每个shared_ptr都会记录当前有多少个shared_ptr指向同一块内存,通过引用计数记录,使用use_count()方法可以获取计数器的数值。
当进行拷贝构造的时候,计数器会递增,当shared_ptr被销毁的时候,计数器会递减,当计数器为0时,就会释放所管理的对象。
auto p=make_shared<int>(111); //当前计数器为1
auto q(p); //计数器递增为2
使用reset()方法可以将当前共享指针的计数器清零并重置指针
shared_ptr<int>p7=make_shared(new int(123));
p7.reset();
不要混合使用普通指针和智能指针
void func(shared_ptr<int> ptr)
{
/*代码段*/
}
int* x=new int(1024);//使用普通指针
func(x); //合法,但是内存会被释放
int y=*x; //报错,x指向的地址被释放
同理,在使用get()方法时要注意不要让它管理的指针被释放
shared_ptr<int>p(new int(1024));
int *q=p.get();//使用q时要注意如果p被释放,q也会悬空
二,weak_ptr类
weak_ptr是一种不控制所指向对象生存期的智能指针,它指向一个shared_ptr管理的对象。使用weak_ptr绑定到一个shared_ptr对象不会改变其引用计数,如果最后一个shared_ptr销毁,对象就会释放。
auto p=make_shared<int>(2);
weak_ptr<int>wp(p);//使用shared_ptr对weak_ptr进行初始化
由于对象有可能不存在,所以不能使用weak_ptr直接访问对象,而是要通过lock()方法才能访问
if(shared_ptr<int>np=wp.lock())//如果np不为空则条件成立
{
//if中,np和p共享对象
}
其他用法
//观察对象的引用计数
np.use_count();
//观测指向对象是否被释放
np.expired();
//重置弱指针指向的对象
np.reset();
std::enable_shared_from_this
class CLA{
public:
CLA(){
std::cout << " CLA() is called" << std::endl;
}
~CLA(){
std::cout << "~CLA() is called" << std::endl;
}
std::shared_ptr<CAL> GetSharedObject(){
return std::shared_ptr<CLA>(this);
}
};
int main()
{
std::shared_ptr<CLA> p(new CLA());
std::shared_ptr<CLA> q = p->GetSharedObject();
std::cout << p.use_count() << std::endl;
std::cout << q.use_count() << std::endl;
return 0;
}
使用shared_ptr管理this时,会出现多次调用析构函数而报错的现象。因此才要用到enable_shared_from_this,其内部是一个weak_ptr,不会影响指向对象的计数器,对象的构造和析构能正常调用
class CLA::public std::enable_shared_from_this<CLA>
{
public:
CLA(){
std::cout << " CLA() is called" << std::endl;
}
~CLA(){
std::cout << "~CLA() is called" << std::endl;
}
std::shared_ptr<CAL> GetSharedObject(){
return shared_from_this();
}
};