C++内存管理之shared_ptr
参考链接:C++内存管理之shared_ptr - 小念之歌 - 博客园 (cnblogs.com)
1. 初始化 sahred_ptr
智能指针的使用方式与普通指针类似。解引用一个智能指针返回它指向的对象。如果在一个条件判断中使用智能指针,效果就是检测它是否为空:
#include <iostream> using namespace std; int main() { /*---------空指针------------*/ shared_ptr<string> p1; if(!p1) //!默认初始化的智能指针中保存着一个空指针!并不是""空字符串 cout<<"p1==NULL"<<endl; /*---------初始化------------*/ shared_ptr<string> p2(new string); if(p2&&p2->empty()){ //!需要注意的时empty时属于string的成员函数。 *p2="helloworld"; cout<<*p2<<endl; } // shared_ptr<int> pa = new int(1);//!error:不允许以暴露裸漏的指针进行赋值操作。 //一般的初始化方式 shared_ptr<string> pint(new string("normal usage!")); cout<<*pint<<endl; //推荐的安全的初始化方式 shared_ptr<string> pint1 = make_shared<string>("safe uage!"); cout<<*pint1<<endl; }
2.关于get()函数;
智能指针定义了一个名为get的函数,它返回一个内置指针,指向智能指针的管理的对象。此函数设置的初衷是当我们向不能使用智能指针的代码传递一个内置指针。使用get返回指针的代码不能delete此指针。
注意:get用来将指针的访问权限传递给代码,只有在确定代码不会delete指针的情况下,才能使用get。特别是,永远不要用get初始化另一个智能指针或者为另一个智能指针赋值!
#include <iostream> #include <memory> using namespace std; void useShared_ptr(int *p) { cout<<*p<<endl; } void delePointer(int *p) { delete p; } int main(int argc, char *argv[]) { shared_ptr<int> p1 = make_shared<int>(32); // shared_ptr<int>p2(p1.get()); //!错误的用法:但是p1、p2各自保留了对一段内存的引用计数,其中有一个引用计数耗尽,资源也就释放了。 useShared_ptr(p1.get()); // delePointer(p1.get()); //!error: return 0; }
3.关于mak_shared函数:
最安全的分配和使用动态内存的方法是调用一个名为make_shared的标准库函数,此函数在动态内存中分配一个对象并初始化它,返回此对象的shared_ptr。与只能指针一样,make_shared也定义在头文件memory中。
#include <iostream> using namespace std; int main() { shared_ptr<int> p3 = make_shared<int>(42); cout<<*p3<<endl; shared_ptr<string> pstr = make_shared<string>("99999"); cout<<*pstr<<endl; shared_ptr<int> pint = make_shared<int>(); //!默认初始化为 0 cout<<*pint<<endl; auto pau = make_shared<string>("auto"); //!更简单,更常用的方式。 cout<<*pau<<endl; }
4.shared_ptr对象的销毁
1)管理动态数组
默认情况下,shared_ptr指向的动态的内存是使用delete来删除的。这和我们手动去调用delete然后调用对象内部的析构函数是一样的。与unique_ptr不同,shared_ptr不直接管理动态数组。如果希望使用shared_ptr管理一个动态数组,必须提供自定义的删除器来替代delete 。
#include <iostream>using namespace std; class DelTest { public: DelTest(){ j= 0; cout<<" DelTest()"<<":"<<i++<<endl; } ~DelTest(){ i = 0; cout<<"~ DelTest()"<<":"<<i++<<endl; } static int i,j; };int DelTest::i = 0;int DelTest::j = 0; void noDefine() { cout<<"no_define start running!"<<endl; shared_ptr<DelTest> p(new DelTest[10]); } void slefDefine() { cout<<"slefDefine start running!"<<endl; shared_ptr<DelTest> p(new DelTest[10],[](DelTest *p){delete[] p;}); } //!传入lambada表达式代替delete操作。 int main() { noDefine(); //!构造10次,析构1次。内存泄漏。 cout<<"----------------------"<<endl; slefDefine(); //!构造次数==析构次数 无内存泄漏 }
2)管理非常规动态对象
某些情况下,有些动态内存也不是我们new出来的,如果要用shared_ptr管理这种动态内存,也要自定义删除器。
#include <iostream>#include <stdio.h> #include <memory> using namespace std; void closePf(FILE * pf) { cout<<"----close pf after works!----"<<endl; fclose(pf); } int main() { // FILE * fp2 = fopen("bin2.txt", "w"); // if(!pf) // return -1; // char *buf = "abcdefg"; // fwrite(buf, 8, 1, fp2); // fclose(fp2); shared_ptr<FILE> pf(fopen("bin2.txt", "w"),closePf); cout<<"*****start working****"<<endl; if(!pf) return -1; char *buf = "abcdefg"; fwrite(buf, 8, 1, pf.get()); //!确保fwrite不会删除指针的情况下,可以将shared_ptr内置指针取出来。 cout<<"----write int file!-----"<<endl; } //!即可以避免异常发生后无法释放内存的问题,也避免了很多人忘记执行fclose的问题。
在这里可以设想一下TCP/IP中链接的打开和关闭的情况,同理都可以使用智能指针来管理。
总结:
最后总结一下上面所陈述的内容,也是shared_ptr使用的基本规范
1)不使用相同的内置指针值初始化(或reset)多个智能指针。
2)不delete get函数返回的指针。
3)如果你使用了get返回的指针,记住当最后一个对应的智能指针销毁后,你的指针就变为无效了。
4)如果你使用智能指针管理的资源不是new分配的内存,记得传递给他一个删除器。
weak_ptr
weakptr使用的比较少,如有兴趣了解,请去参考该篇文章:https://www.cnblogs.com/DswCnblog/p/5628314.html