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

  • Post author:
  • Post category:其他


本小节学习的知识点分别是

智能指针(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_ptr



unique_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的路上~



版权声明:本文为weixin_44980842原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。