0
点赞
收藏
分享

微信扫一扫

智能指针三剑客:shared_ptr

读思意行 04-15 07:30 阅读 1

智能指针简介

在c++中,进行动态内存的分配通常使用new和delete操作符。我们在学习这一对运算符时,一定都听过要注意在使用完new分配到内存后,一定要使用delete手动释放内存,否则就会造成内存的泄露。智能指针就是用来避免这种情况的,智能指针实际上是一个类,它的使用类似于常规指针,但增加了自动内存管理的功能。它会自动删除其所指向的对象,防止内存泄露。而且,当在异常处理中使用动态分配到内存时,智能指针可以确保内存得到正确释放,即使在异常抛出时也是如此。C++98提供了auto_ptr智能指针,不过在C++11之后又推出了shared_ptr、weak_ptr和unique_ptr代替了auto_ptr。C++11标准反对使用auto_ptr。本文仅介绍C++11的三种智能指针。       std::unipue_ptr :独占所有权的智能指针,同一时间内,由其指向的对象不可再被其他指针指向。当然,我们可以移交该对象的指向。当unipue_ptr被销毁时,其指向对象就会被释放。        std::shared_ptr :共享式智能指针,多个共享智能指针可以指向同一个对象,当最后一个指针不再指向该对象时,该对象就会被释放。                                                                                              std::weak_ptr :非拥有所有权的智能指针。它用来指向一个由std::shared_ptr指针管理的对象。它并不参与指向对象的生命周期管理,主要用来观察对象。

shared_ptr定义

std::shared_ptr<int> pi(new int(99));
std::shared_ptr<int> pi=new int(18);//错误示范,智能指针是explicit的,不能用等号进行隐式类型转换

 shared_ptr引用计数的方法:当指向同一个对象的share_ptr指针数目增加时,计数就会相应增加,当shared_ptr数目减少时,计数就会相应减少,直到最后一个shared_ptr被销毁时,也就是计数变为0时,调用其析构函数,就会在析构函数中释放所指向的对象。裸指针可以用来初始化shared_ptr。但为了避免内存空间被重复释放,尽量不要将裸指针(也就是普通指针)与智能指针混用,而且裸指针并不会引起计数的增加。如果我们未在定义时初始化shared_ptr指针默认指向为空。

make_shared

make_shared是标准库中的函数模板,可以安全、高效的初始化share_ptr指针。它的作用是在动态内存中分配并初始化一个对象,并返回指向该对象share_ptr指针。我们可以在()中使用传递类型的所有初始化方式初始化对象。

shared_ptr<int> pi1=make_shared<int>(100);
shared_ptr<string> pi2=make_shared<string>(5,'a');
shared_ptr<int> pi3;//定义时并不初始化,默认为空指针

shared_ptr一般操作

除了和一般指针一样的通过*获得指针指向的对象以外,shared_ptr还有以下功能:use_count()   unique  reset()  get()  swap()  =nullptr

use_count() :返回运行时指向对象的shared_ptr智能指针个数

shared_ptr<int> pi=make_shared<int>(100);
int count=pi.use_count();//1

unique():判断该shared_ptr对象是否独自指向一片内存。

shared_ptr<int> pi=make_shared<int>(100);
if(pi.unique())
    cout<<"就是如此"<<endl;
shared_ptr<int> pi2(pi);
if(!pi2.unique())
    cout<<"yes again"<<endl;

reset():不带参数时:取消该shared_ptr的指向,将该指针置空。如果原指向的对象仅有其一个指向,还要释放指向对象的内存     带参数时:改变shared_ptr的指向,让其指向参数。如果原指向的对象仅有其一个指向,还要释放其内存。参数一般为new的新内存。我们也可以同时reset()初始化空的shared_ptr指针。

shared_ptr<int> pi1=make_shared<int>(520);
shared_ptr<int> pi2=make_shared<int>(1314);
pi1.reset();//置空pi1,释放其指向的内存
pi1=pi2;//让pi1指向与pi2相同的对象
pi2.reset(new int(666));//让pi2指向新new的内存

 get():返回与该智能指针相同指向的裸指针。(不要再手动delete该裸指针)

int *p=shared_ptr<int> pi=make_shared<int>(666);

swap():交换两个智能指针的指向。

shared_ptr<int> pi1=make_shared<int>(520);
shared_ptr<int> pi2=make_shared<int>(1314);
std::swap(pi1,pi2);//交换指向
pi1.swap(pi2);//再交换回去,两种写法作用相同

=nullptr:将智能指针置空,所指向对象的引用计数减一,若该智能指针独自指向一片内存,还有释放该内存。

shared_ptr<int> pi=make_shared<int>(520);
pi=nullptr;//置空pi,释放指向内存

最后shared_ptr名可进行以下判断:

shared_ptr<int> pi=make_shared<int>(520);
if(pi)
{
    cout<<"该指针为空"<<endl;
}
else
{
    cout<<"该指针不为空"<<endl;
}

 指定删除器以及数组问题

我们可以指定我们自定义版本的删除器来代替系统默认生成的删除器,以来进行一些有关需求的操作。这样在引用计数为零时,编译器就会调用我们定义的删除器。

void myDelete(int *p)//删除器
{
    //一些其他操作
    delete p;
}
shared_ptr<int> pi1(new int(666),myDelete);
shared_ptr<int> pi2(new char('a'),[](char *p){
    delete p; 
});//lambda表达式也可以作为删除器

当用智能指针管理动态数组时,应定义自定义的删除器。因为系统默认的删除器并不能处理数组。

或者在shared_ptr传递参数的<>中添加[ ]。(还可以定义一个模板函数封装shared_ptr数组)

void myDelete(int *p)
{
    delete []p;
}
shared_ptr<int> pi1(new int[20],myDelete);

shared_ptr<int []> pi2(new int[20]);
pi2[6]=100;//使用这个方法还可以使pi2可以使用下标访问

template<class T>
shared_ptr<T> make_arrayshared(size_t size)
{
    return shared_ptr<T>(new T[size],[](int *p){
delete []p; 
});
}
shared_ptr<int> pi3= make_arrayshared<int>(5);

 注意:两个shared_ptr智能指针即使删除器不同,但是它们的对象类型仍然相同。

举报

相关推荐

0 条评论