C++11:智能指针
创始人
2024-01-18 08:57:55

常见的内存问题:

  • 重复释放同一块内存会导致程序运行崩溃
  • 没有及时释放不再使用的内存资源,造成内存泄漏,程序占用的内存资源越来越多
  • 有些内存资源已经被释放,但指向它的指针并没有改变指向(成为了野指a

为什么要用智能指针方便和安全的使用动态内存智能指针的行为类似于常规指针 

智能指针的作用:智能指针可以在适当时机自动释放分配的内存,可以很好地避免“忘记释放内存而导致内存泄漏”问题。

头文件:#include 

  • shared_ptr  允许多个指针指向同一个对象
  • unique_ptr  独占这个对象
  • weak_ptr  是一种弱引用指向shared_ptr所管理的对象 

 shared_ptr类:

shared_ptr类似vector,也是一个模板,创建的方式:

	int a = 10;//指向int 的shared_ptrshared_ptrp(&a);//指向a//指向 int的vector 的shared_ptrshared_ptr>p1;//默认初始化为nullptr

shared_ptr类的常用成员函数:

成员方法功能
operator=()重载赋值号,可以相互赋值
operator*()获取shared_ptr所指的数据
operator->()获取内部成员,等价于(*p).men
swap()交换两个相同类型 shared_ptr 智能指针的内容
reset()当函数没有实参时,该函数会使当前 shared_ptr 所指堆内存的引用计数减 1,同时将当前对象重置为一个空指针;当为函数传递一个新申请的堆内存时,则调用该函数的 shared_ptr 对象会获得该存储空间的所有权,并且引用计数的初始值为 1。
get()获得 shared_ptr 对象内部包含的普通指针
use_count()返回同当前 shared_ptr 对象(包括它)指向相同的所有 shared_ptr 对象的数量
unique()判断当前 shared_ptr 对象指向的堆内存,是否不再有其它 shared_ptr 对象再指向它

make_shared(args)

返回一个shared_ptr,指向一个动态分配的类型为T的对象,使用args初始化此对象。

shared_ptr的创建的方式:

	shared_ptrb1;shared_ptrp;//默认初始化shared_ptrp1(b1);//传参shared_ptrp2(new int(42));//指向一个值为42的intshared_ptrp3 = make_shared(10);//使用make_shared初始化

make_shared的使用:

shared_ptr的最安全的分配和使用动态内存的方法,make_shared会返回指向此对象的shared_ptr

    shared_ptrk1 = make_shared(40);shared_ptrk2 = make_shared(5, '3');//字符串可以这样使用 33333shared_ptrk3 = make_shared();//默认为0

 常用auto与make_shared一起使用

    auto g1 = make_shared(50);auto b(g1);//shared_ptr的拷贝

 当一个shared_ptr的计数器变为0时,它会自动释放自己管理的对象

    auto g1 = make_shared(50);auto b(g1);//shared_ptr的赋值auto kk = make_shared(100);//kk指向的int只有一个引用者kk = b;//给kk赋值,指向另一个内存,r原来指向对象的对象计数器-1==0,当计数器等于0时,自动释放内存

shared_ptr自动销毁所管理的对象:

当指向一个对象的最后一个shared_ptr被销毁时,shared_ptr会调用析构函数来完成销毁。shared_ptr的析构函数会递减它所指向对象的引用计数,引用计数为0,析构函数就会销毁对象,并释放内存。注意:shared_ptr还会自动释放相关联的内存

不要把普通指针和智能指针混合使用:

智能指针的使用:

void text(shared_ptrp)//值传递,会传递一个拷贝,拷贝时会增加引用计数
{}
int main()
{shared_ptrp1(new int(20));//p指向一个数据,引用计数为1text(p1);//拷贝时,引用计数+1,变为2//执行完后引用计数-1,变为1int i = *p1;//引用计数为1,没被销毁,正确return 0;
}

以下为错误示范:

void text(shared_ptrp)//值传递,会传递一个拷贝,拷贝时会增加引用计数
{}
int main()
{int* a(new int(20));//一个普通指针text(shared_ptr(a));//合法但内存会被释放int j = *a;//a的内存被释放,a为空悬指针cout << *a << endl;//该值为未定义return 0;
}

不要用get函数去初始化另一个智能指针或为智能指针赋值

	shared_ptr p(new int(20));//引用计数为1int* q = p.get();{shared_ptr(q);//指向相同的内存}//程序块结束后,q被销毁,指向的内存被释放int foo = *p;//未定义,p指向的内存被销毁

 智能指针注意事项:

  • 不使用相同的内置指针初始化或(reset)多个智能指针
  • 不使用get()初始化或reset另一个指针指针
  • 不delete get()返回的指针
  • 使用了get()初始化的指针,当最后一个shared_ptr销毁时,指针变为无效
  • 使用的智能指针管理的资源不是new分配的内存,需要传递一个删除器

unique_ptr 

一个unique_ptr只拥有它所指向的一个对象

由于只能拥有一个对象,那么unique_ptr,不能使用普通的拷贝和赋值操作

在c++11种没有make_unique,来构造一个unique_ptr,但在c++14种新加了 make_unique

unique_ptr的创建:

	unique_ptrp(new int(20));unique_ptrp2();//空指针unique_ptrp3(nullptr);//空指针

无法赋值和拷贝:

	unique_ptrp(new int(20));unique_ptrp1(p);//报错unique_ptrp2;p2 = p;//报错
函数功能
unique_ptr u1空unique_ptr
unique_ptr u2u2会使用一个类型为D的对象来代替delete
unique_ptr u2(d)空unique_ptr,使用一个类型为D的对象来代替delete
u=nullptr释放u指向的对象
u.release()u放弃对指针的控制权,返回指针,并将u置为空
u.reset()释放u所指的对象
u.reset(q)提供了内置指针q,令u指向这个对象,否则将u置为空

unique_ptr不能拷贝和赋值,但可以把控制权转移:

	unique_ptrp(new int(20));unique_ptrp2(p.release());//将控制权转移给p2,把p置空unique_ptrp5(new int(30));unique_ptrp4(move(p5));//使用移动构造函数,p4获得p5的控制权,把p5置为空指针

传递unique_ptr参数和返回unique_ptr

不能拷贝unique_ptr,但可以拷贝或赋值一个将要销毁的unique_ptr

编译器对这种要返回的对象将要销毁,编译器会执行移动构造函数。

unique_ptr text(int p)
{return unique_ptr(new int(p));//返回一个unique_ptr
}
unique_ptr text2(int p)
{unique_ptrk(new int(p));return k;//返回一个局部变量的拷贝
}

weak_ptr

weak_ptr是一种不控制所指向对象生存期的智能指针,指向由shared_ptr管理的对象。 weak_ptr 类型指针的指向和某一 shared_ptr 指针相同时,weak_ptr 指针并不会使所指堆内存的引用计数加 1;同样,当 weak_ptr 指针被释放时,之前所指堆内存的引用计数也不会因此而减 1,weak_ptr是一种“弱”共享对象。

成员函数功能
weak_ptr w空的weak_ptr可以指向类型为T的对象
weak_ptr w(sp)shared_ptr sp 指向相同对象的weak-ptr
w=pp可以是一个shared_ptrh或一个weak_ptr,赋值后共享对象

w.reset()

将w置空
w.use_count()于w共享对象的shared_ptr的数量
w.expired()w.use_count()为0返回true,否则返回false
w.lock()w.expired()为true,返回一个空的shared_ptr,否则返回w指向的对象

weak_ptr 模板类中没有重载 * 和 -> 运算符,这也就意味着,weak_ptr 类型指针只能访问所指的堆内存,而无法修改它 

weak_ptr指针的创建

	weak_ptrgg();//空的weak_ptrshared_ptrp(new int(5));weak_ptrk(p);//指向sharead_ptr对象,弱共享,引用计数不会改变

weak_ptr成员函数的使用

	shared_ptrp(new int(5));weak_ptrk(p);//指向sharead_ptr对象,弱共享,引用计数不会改变shared_ptrk1(k.lock());//k1和k共享对象int i = k.use_count();//获取与k共享的shared_ptr的数量k.reset();//将k置空

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
苁蓉的食用方法 鲜苁蓉的吃法有... 肉苁蓉号称“温而不热,补而不峻,暖而不燥,滑而不泄,故有从容之名。”历来也是传统药食同源的滋补佳品。...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
阳澄湖在哪里哪个省的 阳澄湖是... 点击题目下方苏州生活指南有用 有趣 有态度近期的阳澄湖度很高,3月24日,央视二套《第一时间》直播连...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...