当前位置: 首页 > news >正文

C++学习笔记----6、内存管理(五)---- 智能指针(4)

3、weak_ptr

        在C++中还有一个与shared_ptr相关的智能指针叫做weak_ptr。weak_ptr可以包含一个被shared_ptr管理的资源的引用。weak_ptr自身不拥有资源,所以shared_ptr不被禁止释放资源。当weak_ptr被破坏时(如当其不在活动范围内),weak_ptr不破坏指向的资源;然而,它可以用于决定资源是否被相关shared_ptr释放。weak_ptr的构造函数要求shared_ptr或者另一个weak_ptr作为参数。要访问存储在weak_ptr中的指针,需要将其转化为shared_ptr。有两种方式:

  • 在weak_ptr实例上使用lock()成员函数,它返回一个shared_ptr。如果weak_ptr同时被释放的话它就会返回一个nullptr。
  • 生成一个新的shared_ptr实例,将weak_ptr作为参数传递给shared_ptr构造函数。如果weak_ptr与之相联的shared_ptr被释放的话就会抛出一个std::bad_weak_ptr的例外。

以下的示例展示的weak_ptr的用法:

import std;
using namespace std;class Simple
{
public:Simple() { println("Simple constructor called!"); }~Simple() { println("Simple destructor called!"); }
};void useResource(weak_ptr<Simple>& weakSimple)
{auto resource{ weakSimple.lock() };if (resource) {println("Resource still alive.");}else {println("Resource has been freed!");}
}int main()
{auto sharedSimple{ make_shared<Simple>() };weak_ptr<Simple> weakSimple{ sharedSimple };// Try to use the weak_ptr.useResource(weakSimple);// Reset the shared_ptr.// Since there is only 1 shared_ptr to the Simple resource, this will// free the resource, even though there is still a weak_ptr alive.sharedSimple.reset();// Try to use the weak_ptr a second time.useResource(weakSimple);
}

结果如下:

Simple constructor called!
Resource still alive.
Simple destructor called!
Resource has been freed!

weak_ptr也支持C风格的数组,与shared_ptr一样。

4、传参给函数

        只有在传递属主或者属主共享存在的时候,能够接受指针作为其参数也应该接受智能指针。为了共享shard_ptr的属主,只接受通过值的shared_ptr作为参数。同样的,为了传递unique_ptr的属主,只接受通过值的unique_ptr作为参数。后者要求使用move的语法,我们以后再讨论。

        如果既没有属主传递也没有属主共享介入,函数只有reference-­to-­non-­const或者 reference-­to-­const参数指向其背后的资源,或者是一个原始指南指向它,如果nullptr是有效参数的话。像const shared_ptr<T>& 或者const unique_ptr<T>&这样的参数类型是没有什么道理的。

5、函数返回值

        标准智能指针shared_ptr,unique_ptr,以及weak_ptr通过值可以容易且有效地从函数返回,得益于强制与非强制的拷贝省略以及移动的语法。移动的语法目前并不重要。重要的是这些方式从函数中返回一个智能指针都是高效的。例如,可以写出如下的create()函数,在main()中如示例使用:

import std;
using namespace std;class Simple
{
public:Simple() { println("Simple constructor called!"); }~Simple() { println("Simple destructor called!"); }
};unique_ptr<Simple> create()
{auto ptr{ make_unique<Simple>() };// Do something with ptr...return ptr;
}int main()
{unique_ptr<Simple> mySmartPtr1{ create() };auto mySmartPtr2{ create() };
}

6、enable_shared_from_this

        从std::enable_shared_from_this继承一个类允许成员函数被在一个安全返回shared_ptr或者weak_ptr给自身的对象调用。没有这个基类,一种方式就是返回一个有效的shared_ptr或者weak_ptr给this,通过给类加一个weak_ptr作为成员,返回其复本或者返回由其构造的shared_ptr。enable_shared_from_this类添加了如下的两个成员函数给其继承的类:

  • shared_from_this():返回一个共享对象属主的shared_ptr。
  • weak_from_this():返回一个跟踪对象属主的weak_ptr。

        这个高级属性我们不进行详细讨论,但是下面的代码展示了其用途。share_from_this()与weak_from_this()为公共成员函数。然而,你可能会发现from_this部分在公共接口时有点令人搞不懂,只是作为一个展示,下面的Foo类定义了它自身的成员函数getPointer():

import std;
using namespace std;class Foo : public enable_shared_from_this<Foo>
{
public:shared_ptr<Foo> getPointer() {return shared_from_this();}
};int main()
{auto ptr1{ make_shared<Foo>() };auto ptr2{ ptr1->getPointer() };
}

        注意:只有在指针已经被保存在shared_ptr时才可以在对象上使用shared_from_this();否则的话,就会抛出bad_weak_ptr的例外。在上面的例子中,make_shared()在main()中用于生成一个叫做ptr1的shared_ptr,它包含一个Foo的实例。shared_ptr生成之后,允许在Foo实例上调用shared_from_this()。另一方面,调用weak_from_this()总是可以的,只是如果在一个没有存储在shared_ptr的指针上的对象进行调用就可能会返回空的weak_ptr。

下面的代码是对getPointer()成员函数的彻头彻尾的错误应用:

class Foo
{
public:shared_ptr<Foo> getPointer() {return shared_ptr<Foo>(this);}
};

        如果像刚展示的那样在main()中使用同样的代码,对Foo的应用就会产生双重删除。两个完全独立的shared_ptr(ptr1与ptr2)指向了同一个对象,都会在其不在活动范围时尝试去删除该对象。

7、智能指针与C风格的函数的互操作性(c++23特性)

        通常情况下,C风格的函数使用返回类型来显示函数是否正确执行或者是否有错误。既然返回类型早就用于报告错误,那另外的输出参数就用于函数返回其他的数据。例如:

using errorcode = int;errorcode my_alloc(int value, int** data)
{*data = new int{ value };println("Allocated");return 0;
}errorcode my_free(int* data)
{delete data;println("Freed");return 0;
}

        这种C风格的API,my_alloc()函数返回了一个errorcode,在输出的data参数中返回了分配的数据。在c++23之前,不能在my_alloc()中直接使用智能指针,比如unique_ptr。那你可以这样做:

		unique_ptr<int, decltype(&my_free)> myIntSmartPtr(nullptr, my_free);int* data{ nullptr };my_alloc(42, &data);myIntSmartPtr.reset(data);

        这个也比较容易吧。c++23引入了std::out_ptr与inout_ptr()函数来帮助做这些,定义在<memory>中,使用该函数,上面的代码片断就可以写得更优雅:

		unique_ptr<int, decltype(&my_free)> myIntSmartPtr(nullptr, my_free);my_alloc(42, inout_ptr(myIntSmartPtr));

        如果你确信传递给inout_ptr的指针为nullptr,也可以使用out_ptr。

8、旧的已经移除的auto_ptr

        旧的,c++11之前的标准库包含了一个智能指针的基本实现,叫做auto_ptr。很不幸,auto_ptr有很严重的缺点。其中一个就是当在比如vector这样的标准库构造函数中使用时不能正确工作。c++官方废除了auto_ptr,从c++17开始,从标准库中完全移除掉了。它被unique_ptr与shared_ptr替换掉了。这里提到auto_ptr是为了确认你了解这一点并且 确认不会用到它。

        不要使用旧的auto_ptr智能指针!要使用unique_ptr,如果需要共享属主就使用shared_ptr。


http://www.mrgr.cn/news/25425.html

相关文章:

  • Harmony Next 文件命令操作(发送、读取、媒体文件查询)
  • Python实现模糊逻辑算法
  • 基于ESP32S3的链接大语言模型对话模块
  • 算法刷题:300. 最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组
  • 一文读懂多组学联合分析产品在医学领域的应用
  • 模拟实现计算器(switch函数实现与转移表实现)
  • 【Linux 19】线程概念
  • Unity基本操作
  • 【linux】一种基于虚拟串口的方式使两个应用通讯
  • 通信工程学习:什么是SDH同步数字体系
  • 大模型国产化算力方案
  • c++11——share_ptr的助手weak_ptr
  • 前端 + 接口请求实现 vue 动态路由
  • buck boost Ldo 经典模型的默写
  • 排序题目:一手顺子
  • 【办公】会议纪要模板
  • OJ 两两交换链表中的节点
  • MySQL之库和表操作
  • Python容器一之字符串
  • 好看好听的小猪包扩音器,轻巧便携更好用,得胜E10上手