Th5.6:智能指针(unique_ptr)之详述1

本小节学习的知识点分别是智能指针(unique_ptr)之详述、常用操作。

今天总结的知识分为以下2个大点:

(1)unique_ptr概述、常用操作
    (1.1)常规初始化(unique_ptr和new配合)
    (1.2)make_unique()函数
(2)unique_ptr的常用操作
    (2.1)unique_ptr不支持的操作
    (2.2)移动语义
    (2.3)release()
    (2.4)reset()
    (2.5)=nullptr
    (2.6)指向一个数组
    (2.7)get()
    (2.8)*解引用
    (2.9)swap()
    (2.10)智能指针的名字作为判断条件
    (2.11)转换为sahred_ptr类型

(1)unique_ptr概述、常用操作:

        unique_ptr:独占式(专属)的指针。(所谓独占式,也即同一时刻,是一个unique_ptr智能指针只能指向对应的一个对象(这块内存))当该unique_ptr指针被销毁时,其所指向的内存就会给释放掉。(Boost库中的scoped_ptrunique_ptr类似!它也是独占式的智能指针)
    (1.1)常规初始化(unique_ptr和new配合):

unique_ptr<int> unptr1;
//unptr1是指向一个int型对象的空指针
unique_ptr<int> unptr2(new int(12));
//unptr2是指向一个int型对象val为12的unique_ptr智能指针

   (1.2)make_unique()函数(推荐使用):

        make_unique()函数是C++14中才引入的,C++11时还没引入这么个函数。当然,和shared_ptr的make_shared()函数一样,它们都不支持指定删除器的功能!若你想自定义删除器deleter的话,就不能使用make_unique()函数啦!

unique_ptr<double> unptr3 = make_unique<double>(1.88);
//unptr2是指向一个double型对象val为1.88的unique_ptr智能指针
auto unptr4 = make_unique<float>(1.98f);
//unptr4是指向一个float型对象val为1.98f的unique_ptr智能指针

(2)unique_ptr的常用操作:

        (2.1)unique_ptr不支持的操作:

        unique_ptr智能指针不支持拷贝以及赋值给别的指针这样的操作!

unique_ptr<string> ptr1 = make_unique<string>("I Love China!");
//unique_ptr<string> ptr2(ptr1);//❌!
//unique_ptr<string> ptr3 = ptr1;//❌!
//unique_ptr<string> ptr4;//❌!
//ptr4 = ptr1;//❌!
//这些代码都是错误的!因为unique_ptr这个指针不支持这些拷贝和赋值给别的指针的操作!

        (2.2)移动语义:

        用std::move()函数将一个unique_ptr指针所指向内存的控制权限移动(交给)给另一个unique_ptr指针,此时原来的unique_ptr指针就置为nullptr(且根据使用move函数的规则,你一旦移动完之后,就不能再对原来的指针do事情了!)

unique_ptr<string> ptr1 = make_unique<string>("I Love China!");
unique_ptr<string> ptr2(std::move(ptr1));
//cout << "*ptr1" << *ptr1 << endl;//构造函数将ptr1的内存控制权限移动给(交给)了ptr2
cout << "*ptr2 = " << *ptr2 << endl;

运行调试结果:

        在执行unique_ptr<string> ptr2(std::move(ptr1));这行代码之前的调试结果:

         在执行unique_ptr<string> ptr2(std::move(ptr1));这行代码之后的调试结果:

     (2.3).release():

        .release()方法的作用:放弃对该unique_ptr指针所指向对象的资源管理权。人话:将该unique_ptr指针置为nullptr的同时,返回其所指向的这个裸指针。当然,一旦你要用.release()方法这么do时,必须手动释放该裸指针所指向的内存!

一般对unique_ptr指针使用.release()方法时都要写如下三行codes

delete语句以及用一个对应类型的指针变量来接住指针所指向的裸指针语句这2行代码是缺一不可的

unique_ptr<double> unptr1 = make_unique<double>(8.88);
auto  ptr = unptr1.release();
delete ptr;//释放内存!若你不释放的话,unique_ptr这个类模板内部给你new的指针你就没释放
//这就会造成内存泄露leakage!

调试运行结果:

再比如:

unique_ptr<double> unptr1 = make_unique<double>(8.88);
unique_ptr<double> unptr2(unptr1.release());
//将unptr1所指向的double*的裸指针绑定到unptr2这个unique_ptr智能指针上!
unptr2.release();//直接release掉但是并没有手动释放unptr2所指向的double*裸指针的话
//就会造成内存泄露leakage!

运行调试结果:

        在unique_ptr<double> unptr2(unptr1.release());这行代码执行前的调试运行结果:

        在unique_ptr<double> unptr2(unptr1.release());这行代码执行后调试运行结果:

     (2.4).reset():

        a).reset(不带参数)方法的作用:释放 unique_ptr指针所指向的对象,并将该指针置为nullptr(空)。

unique_ptr<int> unptr = make_unique<int>(89);
unptr.reset();//将unptr置为nullptr并释放其原来所指向对象的内存!
if (unptr == nullptr)cout << "unptr == 空!" << endl;

        b).reset(新的指针对象)方法的功能:释放unique_ptr指针所指向的原对象,并将该指针置为新的指针对象。

unique_ptr<int> unptr = make_unique<int>(89);
unptr.reset(new int(888));//将unptr置为int型的对象888并释放其原来所指向对象的内存!
cout << *unptr << endl;//result = 888
	//or
unique_ptr<int> unptr1 = make_unique<int>(11);
unique_ptr<int> unptr2 = make_unique<int>(22);
unptr2.reset(unptr1.release());//将unptr置为unptr1指向的对象,并释放unptr2原所指向对象的内存!
cout << *unptr2 << endl;//result = 11

    (2.5)=nullptr:

        =nullptr方法的作用:将该unique_ptr指针置为nullptr空,并释放其所指向的对象。

unique_ptr<int> uniptr(new int(188));
uniptr = nullptr;//此时会释放uniptr所指向的对象,并且uniptr置空nullptr

    (2.6)指向一个数组:

        当unique_ptr智能指针指向一个数组对象时,<内就要加上elemTypeName[]>

unique_ptr<int[]> parr(new int[2]);
//注意:当unique_ptr智能指针指向一个数组时,<内就要加上elemType[]>
parr[0] = 1;
parr[1] = 12;
cout << parr[0] << endl;//result: 1
cout << parr[1] << endl;//result: 12

unique_ptr<A[]> parr2(new A[2]);
//这个unique_ptr智能指针指向一个A类型的且只有2个元素的数组

    (2.7).get():

        .get()方法的作用:返回unique_ptr智能指针所保存的裸指针。(正因为有些第三方库函数需要用到内置的裸指针,所以就引入该函数)

        注意①:用来.get()方法后,务必要记得不要释放该裸指针(delete p)所指向的内存,因为你这么干那你为啥还需要用unique_ptr这个智能指针来帮你管理内存呢?对吧?

        注意②:务必要记得不要将该裸指针所指向的内存绑定到另一个unique_ptr指针身上,因为你这么干会造成重复释放同一内存空间的异常问题。

unique_ptr<string> ptr1(new string("I Love China!"));
//*ptr1 = "I Love China!"
string * tp = ptr1.get();
*tp = "I Love you!";
//*tp = "I Love you!"

    (2.8)*解引用:

        与普通指针一样,智能指针也可以用*号do解引用,作用:获取该指针所指向的对象!

unique_ptr<string> ptr1(new string("I Love China!"));
cout << "*ptr1 = "<< * ptr1 << endl;
//*ptr1 = "I Love China!"
unique_ptr<string> ptr2(new string("You Love China!"));
cout << "*ptr2 = " << *ptr2 << endl;
//*ptr1 = "You Love China!"

unique_ptr<int[]> pp(new int[11]);
//对于数组,可直接用指针名+[index]来访问对应的elem
pp[0] = 0;
pp[1] = 1;

    (2.9)swap():

        .swap()方法的作用:用于交换2个unique_ptr智能指针所指向的对象!

unique_ptr<string> ps1(new string("lzf1"));
unique_ptr<string> ps2(new string("lzf2"));
cout <<"std::swap前:*ps1 = " <<*ps1 << " *ps2 = " << *ps2 << endl;
std::swap(ps1, ps2);
cout << "std::swap后:*ps1 = " << *ps1 << " *ps2 = " << *ps2 << endl;
ps1.swap(ps2);
cout << ".swap后:*ps1 = " << *ps1 << " *ps2 = " << *ps2 << endl;

运行结果:

     (2.10)智能指针的名字作为判断条件:

        用unique_ptr智能指针的名字作为if语句的判断条件。

unique_ptr<int> ptr(new int(1));
if (ptr)cout << "ptr非空!" << endl;
else cout << "ptr为空!" << endl;
ptr.reset();
if (ptr)cout << "ptr非空!" << endl;
else cout << "ptr为空!" << endl;


    (2.11)转换为shared_ptr类型:

        因为shared_ptr指针类模板中,含有显式构造函数,这个构造函数可用于将右值的unique_ptr指针转换为shared_ptr指针!

显式构造函数的源码:

explicit shared_ptr(_Ux* _Px) { // construct shared_ptr object that owns _Px
    if constexpr (is_array_v<_Ty>) {
        _Setpd(_Px, default_delete<_Ux[]>{});
    }else {
        _Temporary_owner<_Ux> _Owner(_Px);
        _Set_ptr_rep_and_enable_shared(_Owner._Ptr, new _Ref_count<_Ux>(_Owner._Ptr));
        _Owner._Ptr = nullptr;
    }
}

例子1:

unique_ptr<string> puns(new string("I Love China!"));
//puns是一个左值!
shared_ptr<string> ps1 = puns;//❌错误!
shared_ptr<string> ps2 = std::move(puns);//√!

例子2:

auto myfunc() {
	return unique_ptr<string>(new string("I Love China!"));
	//这是一个右值,因为这个return的临时对象肯定就是“右值”昂!!!
}
shared_ptr<string> ps1 = myfunc();//√!

临时对象一定是一个右值!所以可以将一个临时的unique_ptr指针转换为shared_ptr指针。

运行结果:

 不能将左值的unique_ptr转换为shared_ptr!

 对于:

unique_ptr<string> puns(new string("I Love China!"));
//puns是一个左值!
//shared_ptr<string> ps1 = puns;//❌错误!
shared_ptr<string> ps2 = std::move(puns);

运行调试结果:

        在运行shared_ptr<string> ps2 = std::move(puns);这行代码之前的调试结果:

         在运行shared_ptr<string> ps2 = std::move(puns);这行代码之后的调试结果:

        std::move()函数会将对象(这个左值)变为一个右值,同时将该左值置为空。(人话:就是将这个左值所占据的内存空间的管理权限直接移动给新的对象,原对象对这块内存空间就没有管理权限了--》置空!)

        以上就是我总结的关于智能指针(unique_ptr)之详述、常用操作的笔记。希望你能读懂并且消化完,也希望自己能牢记这些小小的细节知识点,加油吧,我们都在coding的路上~

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fanfan21ya

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值