本小节学习的知识点分别是智能指针(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指针被销毁时,其所指向的内存就会给释放掉。
(1.1)常规初始化(unique_ptr和new配合):
unique_ptrunptr1; //unptr1是指向一个int型对象的空指针 unique_ptr 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_ptrunptr3 = make_unique (1.88); //unptr2是指向一个double型对象val为1.88的unique_ptr智能指针 auto unptr4 = make_unique (1.98f); //unptr4是指向一个float型对象val为1.98f的unique_ptr智能指针
(2)unique_ptr的常用 *** 作:
(2.1)unique_ptr不支持的 *** 作:
unique_ptr智能指针不支持拷贝以及赋值给别的指针这样的 *** 作!
unique_ptrptr1 = make_unique ("I Love China!"); //unique_ptr ptr2(ptr1);//❌! //unique_ptr ptr3 = ptr1;//❌! //unique_ptr ptr4;//❌! //ptr4 = ptr1;//❌! //这些代码都是错误的!因为unique_ptr这个指针不支持这些拷贝和赋值给别的指针的 *** 作!
(2.2)移动语义:
用std::move()函数将一个unique_ptr指针所指向内存的控制权限移动(交给)给另一个unique_ptr指针,此时原来的unique_ptr指针就置为nullptr(且根据使用move函数的规则,你一旦移动完之后,就不能再对原来的指针do事情了!)
unique_ptrptr1 = make_unique ("I Love China!"); unique_ptr ptr2(std::move(ptr1)); //cout << "*ptr1" << *ptr1 << endl;//构造函数将ptr1的内存控制权限移动给(交给)了ptr2 cout << "*ptr2 = " << *ptr2 << endl;
运行调试结果:
在执行unique_ptr
在执行unique_ptr
(2.3).release():
.release()方法的作用:放弃对该unique_ptr指针所指向对象的资源管理权。人话:将该unique_ptr指针置为nullptr的同时,返回其所指向的这个裸指针。当然,一旦你要用.release()方法这么do时,必须要手动释放该裸指针所指向的内存!
一般对unique_ptr指针使用.release()方法时都要写如下三行codes:
(delete语句以及用一个对应类型的指针变量来接住指针所指向的裸指针语句这2行代码是缺一不可的)
unique_ptrunptr1 = make_unique (8.88); auto ptr = unptr1.release(); delete ptr;//释放内存!若你不释放的话,unique_ptr这个类模板内部给你new的指针你就没释放 //这就会造成内存泄露leakage!
调试运行结果:
再比如:
unique_ptrunptr1 = make_unique (8.88); unique_ptr unptr2(unptr1.release()); //将unptr1所指向的double*的裸指针绑定到unptr2这个unique_ptr智能指针上! unptr2.release();//直接release掉但是并没有手动释放unptr2所指向的double*裸指针的话 //就会造成内存泄露leakage!
运行调试结果:
在unique_ptr
在unique_ptr
(2.4).reset():
a).reset(不带参数)方法的作用:释放 unique_ptr指针所指向的对象,并将该指针置为nullptr(空)。
unique_ptrunptr = make_unique (89); unptr.reset();//将unptr置为nullptr并释放其原来所指向对象的内存! if (unptr == nullptr)cout << "unptr == 空!" << endl;
b).reset(新的指针对象)方法的功能:释放unique_ptr指针所指向的原对象,并将该指针置为新的指针对象。
unique_ptrunptr = make_unique (89); unptr.reset(new int(888));//将unptr置为int型的对象888并释放其原来所指向对象的内存! cout << *unptr << endl;//result = 888 //or unique_ptr unptr1 = make_unique (11); unique_ptr unptr2 = make_unique (22); unptr2.reset(unptr1.release());//将unptr置为unptr1指向的对象,并释放unptr2原所指向对象的内存! cout << *unptr2 << endl;//result = 11
(2.5)=nullptr:
=nullptr方法的作用:将该unique_ptr指针置为nullptr空,并释放其所指向的对象。
unique_ptruniptr(new int(188)); uniptr = nullptr;//此时会释放uniptr所指向的对象,并且uniptr置空nullptr
(2.6)指向一个数组:
当unique_ptr智能指针指向一个数组对象时,<内就要加上elemTypeName[]>
unique_ptrparr(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 parr2(new A[2]); //这个unique_ptr智能指针指向一个A类型的且只有2个元素的数组
(2.7).get():
.get()方法的作用:返回unique_ptr智能指针所保存的裸指针。(正因为有些第三方库函数需要用到内置的裸指针,所以就引入该函数)
注意①:用来.get()方法后,务必要记得不要释放该裸指针(delete p)所指向的内存,因为你这么干那你为啥还需要用unique_ptr这个智能指针来帮你管理内存呢?对吧?
注意②:务必要记得不要将该裸指针所指向的内存绑定到另一个unique_ptr指针身上,因为你这么干会造成重复释放同一内存空间的异常问题。
unique_ptrptr1(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_ptrptr1(new string("I Love China!")); cout << "*ptr1 = "<< * ptr1 << endl; //*ptr1 = "I Love China!" unique_ptr ptr2(new string("You Love China!")); cout << "*ptr2 = " << *ptr2 << endl; //*ptr1 = "You Love China!" unique_ptr pp(new int[11]); //对于数组,可直接用指针名+[index]来访问对应的elem pp[0] = 0; pp[1] = 1;
(2.9)swap():
.swap()方法的作用:用于交换2个unique_ptr智能指针所指向的对象!
unique_ptrps1(new string("lzf1")); unique_ptr 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_ptrptr(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_ptrpuns(new string("I Love China!")); //puns是一个左值! shared_ptr ps1 = puns;//❌错误! shared_ptr ps2 = std::move(puns);//√!
例子2:
auto myfunc() { return unique_ptr(new string("I Love China!")); //这是一个右值,因为这个return的临时对象肯定就是“右值”昂!!! } shared_ptr ps1 = myfunc();//√!
临时对象一定是一个右值!所以可以将一个临时的unique_ptr指针转换为shared_ptr指针。
运行结果:
不能将左值的unique_ptr转换为shared_ptr!
对于:
unique_ptrpuns(new string("I Love China!")); //puns是一个左值! //shared_ptr ps1 = puns;//❌错误! shared_ptr ps2 = std::move(puns);
运行调试结果:
在运行shared_ptr
在运行shared_ptr
std::move()函数会将对象(这个左值)变为一个右值,同时将该左值置为空。(人话:就是将这个左值所占据的内存空间的管理权限直接移动给新的对象,原对象对这块内存空间就没有管理权限了--》置空!)
以上就是我总结的关于智能指针(unique_ptr)之详述、常用 *** 作的笔记。希望你能读懂并且消化完,也希望自己能牢记这些小小的细节知识点,加油吧,我们都在coding的路上~
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)