2020.4.15 之前一直不愿意用智能指针,想法是因为现在项目不是足够大,认为没必要担心内存泄露的问题,自己控制好即可。这几天在认真拜读陈硕大佬的《c++多线程服务器编程》,认为是一本非常优秀的书籍,很适合我这种从初级往中级程序员发展突破“境界”所用。书里说了一些多线程的原理,c++多线程中使用智能指针是非常合适的,因为没有垃圾回收机制,在对象析构过程中多线程访问对象难免会出问题,不想自己重复造轮子,智能指针是非常合适的选择,原因会在之后分析,当然是借鉴了书中的一些想法。
下列博客讲的很好
https://www.cyhone.com/articles/right-way-to-use-cpp-smart-pointer/
一.基础用法
1.shared_ptr
shared_ptr<string>p1; //这里声明+定义初始化的时候 已经初始化为0 不用担心野指针的问题。
shared_ptr<string>pi(new string("hello gyf"));
一般初始化
shared_ptr<string>pi(new string("hello gyf"));
推荐的安全的初始化方式
shared_ptr<string> pint1 = make_shared<string>("safe uage!");
尽量不要将 shared_ptr指向一个普通指针。
尽量不要用到get()函数 get用来将指针的访问权限传递给代码,只有在确定代码不会delete指针的情况下,才能使用get。特别是,永远不要用get初始化另一个智能指针或者为另一个智能指针赋值。
尽量不使用get()呗
关于mak_shared函数:
最安全的分配和使用动态内存的方法是调用一个名为make_shared的标准库函数,此函数在动态内存中分配一个对象并初始化它,返回此对象的shared_ptr。与只能指针一样,make_shared也定义在头文件memory中。
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;
cout<<p.use_count()<<endl; 这个函数可以知道当前有多少个其他智能指针指向这个对象。
reset()函数
reset会更新(-1)引用计数,如果需要的话,会释放p1指向的对象。reset成员经常与unique一起使用,来控制多个shared_ptr的共享对象。在改变底层对象之前,我们在检查自己是否是当前对象仅有的用户。
反正reset会把当前指针计为空 对象引用计数减1 如果对象引用计数为0 直接析构该对象。
容器中的shared_ptr-记得用erease节省内存
对于一块内存,shared_ptr类保证只要有任何shared_ptr对象引用它,他就不会被释放掉。由于这个特性,保证shared_ptr在不用之后不再保留就非常重要了,通常这个过程能够自动执行而不需要人工干预,有一种例外就是我们将shared_ptr放在了容器中。所以永远不要忘记erease不用的shared_ptr。
总结
1)不使用相同的内置指针值初始化(或reset)多个智能指针。
2)不delete get函数返回的指针。
3)如果你使用了get返回的指针,记住当最后一个对应的智能指针销毁后,你的指针就变为无效了。
4)如果你使用智能指针管理的资源不是new分配的内存,记得传递给他一个删除器。
2.weak_ptr
1、weak_ptr是什么?
weak_ptr是为了配合shared_ptr而引入的一种智能指针,它指向一个由shared_ptr管理的对象而不影响所指对象的生命周期,也就是将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。不论是否有weak_ptr指向,一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放。从这个角度看,weak_ptr更像是shared_ptr的一个助手而不是智能指针。
2、weak_ptr如何使用?
接下来,我们来看看weak_ptr的简单用法。
2.1如何创建weak_ptr实例
当我们创建一个weak_ptr时,需要用一个shared_ptr实例来初始化weak_ptr,由于是弱共享,weak_ptr的创建并不会影响shared_ptr的引用计数值。
具体看这个博文 非常清楚
https://blog.csdn.net/albertsh/article/details/82286999
3.unique_ptr
我们大多数场景下用到的应该都是 unique_ptr。
unique_ptr 代表的是专属所有权,即由 unique_ptr 管理的内存,只能被一个对象持有。
所以,unique_ptr 不支持复制和赋值,如下:
| |
如果想要把 w 复制给 w2, 是不可以的。因为复制从语义上来说,两个对象将共享同一块内存。
因此,unique_ptr 只支持移动, 即如下:
| |
unique_ptr 代表的是专属所有权,如果想要把一个 unique_ptr 的内存交给另外一个 unique_ptr 对象管理。只能使用 std::move 转移当前对象的所有权。转移之后,当前对象不再持有此内存,新的对象将获得专属所有权。
如上代码中,将 w 对象的所有权转移给 w2 后,w 此时等于 nullptr,而 w2 获得了专属所有权。