本小节学习的知识点分别是
智能指针(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的路上~