热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

RAII是否支持资源所有权转移?

我过去主要认为RAII是关于使用对象生命周期来避免资源泄漏,这在实践中对我来说已经足够好了。但是我最近讨论了什么是RAII模式,什么不是,这让我在网上搜索了更多的定义和评论,结果增

我过去主要认为 RAII 是关于使用对象生命周期来避免资源泄漏,这在实践中对我来说已经足够好了。但是我最近讨论了什么是 RAII 模式,什么不是,这让我在网上搜索了更多的定义和评论,结果增加了更多的混乱而不是清晰。

RAII 类的标准定义似乎需要两个属性:


  1. RAII 类的构造函数应该获取资源或在该过程中失败时抛出异常。

  2. RAII 类的析构函数应该释放资源。

但后来我也看到在一些 RAII 定义中提到资源所有权可以在此类 RAII 类的实例之间“安全转移”。因此,资源所有权转移似乎被接受为 RAII 模式的一部分。

但是,似乎资源所有权转移也会导致打破似乎定义 RAII 的那两个属性。

假设我有两个 RAII 类的实例 -Instance_SourceInstance_Destination- 并且我将基础资源的所有权从Instance_Source转移到Instance_Destination。然后我们有:


  • 与属性 2 的冲突:

    • 的析构函数Instance_Source不会释放任何资源,所以我们现在打破了析构函数应该释放资源的要求。



  • 与属性 1 的冲突:

    • 在初始化中获取资源的优点之一是我可以使用知道它们包含有效资源的实例(否则它们不会被构造)。但是随着所有权转移,我现在剩下的实例不再包含有效资源,这消除了在构造函数中获取资源应该带来的主要优势。

    • 在某些情况下,我不想Instance_Destination在构建过程中获取任何资源,因为我希望它只Instance_Source在特殊条件下获得所获取内容的所有权。为了支持这样的场景,我必须打破构造函数获取资源的要求,允许在Instance_Destination不获取任何资源的情况下进行初始化。



因此,在我需要允许资源所有权转移的情况下,我发现我必须“松散”处理关于在构造函数中获取资源并在析构函数中释放它们的 2 RAII 要求。这在实践中效果很好,但它是否仍然构成理论上的 RAII 模式?

这就是我提出问题的原因:RAII 是否支持资源所有权转移?

如果答案是yes,那么看起来大多数 RAII 定义应该重新设计,不依赖于构造函数和析构函数应该对资源做什么。

如果答案是否定的,那么这应该被强调为 RAII 的一个重要限制。

回答



RAII 是否支持资源所有权转移?

可以,是的。

但是,似乎资源所有权转移也会导致打破似乎定义 RAII 的那两个属性。

有点取决于人们如何定义 RAII 的细节。


解决方案是扩展问题中显示的 RAII 的定义,以允许表示空状态。如果存在空状态的表示,则可以通过将源 RAII 对象保留在这种空状态来移动资源的所有权。

构建和销毁问题中给出的定义对此进行调整是微不足道的:


  1. 构造要么获取资源,要么初始化为空状态。从技术上讲,这不是必需的,但如果允许空状态,则允许默认构造很方便。

  2. 析构函数释放资源当且仅当它拥有任何资源。

  3. 如前一段所述的移动的附加定义。

标准库中的大多数 RAII 类都有空状态的表示,并且那些支持传输它们的资源。此类 RAII 类及其空状态的典型示例:


  • 任何动态容器 - 不包含任何元素(并且有空容量)的容器

  • 任何智能指针 - 空值

  • std::fstream - 与文件无关的流

  • std::thread - 与线程无关的包装器

标准库也有 RAII 类,它们没有空状态的表示,因此不能支持资源的传输。这种类的一个例子是std::lock_guard.



我希望有人也可以提供一个历史的观点

我所拥有的定义的最古老来源是 Stroustrup 的书“C++ 编程语言第 3 版”。根据维基百科的估计,RAII 是在 1984-89 年左右开发的,所以到这本书出版时,它已经是一个 8-13 岁的想法。以下是最相关的部分,希望不会太多侵犯版权:

14.4.1 使用构造函数和析构函数

使用本地对象管理资源的技术通常被称为“资源获取即初始化”。这是一种通用技术,它依赖于构造函数和析构函数的属性以及它们与异常处理的交互。

...

构造函数试图确保其对象被完整且正确地构造。当无法实现时,编写良好的构造函数会尽可能地将系统状态恢复到创建之前的状态。


14.4.2 Auto_ptr

... auto_ptr,支持“资源获取即初始化”技术。

鉴于它std::auto_ptr不一定拥有资源,因此它的析构函数在这种情况下不会释放资源,它可以将资源转移到另一个实例,而创造 RAII 的作者认为std::auto_ptr“支持 RAII”,我有信心说与问题中描述的属性相冲突并不取消 RAII 的资格。

请注意,std::auto_ptr 已被 C++11 中移动语义的引入所淘汰,此后已从语言中删除。

E.3.5.3 延迟资源获取

...每当类的语义不要求延迟资源获取时,就应该在构造函数中获取资源

我没有发现关于 RAII 如何与转移资源所有权的能力相关的明确描述。我怀疑在为具有移动语义的语言编写的后续版本中可能会更多地讨论它。






推荐阅读
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • MyBatis错题分析解析及注意事项
    本文对MyBatis的错题进行了分析和解析,同时介绍了使用MyBatis时需要注意的一些事项,如resultMap的使用、SqlSession和SqlSessionFactory的获取方式、动态SQL中的else元素和when元素的使用、resource属性和url属性的配置方式、typeAliases的使用方法等。同时还指出了在属性名与查询字段名不一致时需要使用resultMap进行结果映射,而不能使用resultType。 ... [详细]
  • Tomcat/Jetty为何选择扩展线程池而不是使用JDK原生线程池?
    本文探讨了Tomcat和Jetty选择扩展线程池而不是使用JDK原生线程池的原因。通过比较IO密集型任务和CPU密集型任务的特点,解释了为何Tomcat和Jetty需要扩展线程池来提高并发度和任务处理速度。同时,介绍了JDK原生线程池的工作流程。 ... [详细]
  • 本文介绍了作者在开发过程中遇到的问题,即播放框架内容安全策略设置不起作用的错误。作者通过使用编译时依赖注入的方式解决了这个问题,并分享了解决方案。文章详细描述了问题的出现情况、错误输出内容以及解决方案的具体步骤。如果你也遇到了类似的问题,本文可能对你有一定的参考价值。 ... [详细]
  • 本文讨论了在数据库打开和关闭状态下,重新命名或移动数据文件和日志文件的情况。针对性能和维护原因,需要将数据库文件移动到不同的磁盘上或重新分配到新的磁盘上的情况,以及在操作系统级别移动或重命名数据文件但未在数据库层进行重命名导致报错的情况。通过三个方面进行讨论。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 标题: ... [详细]
  • mac php错误日志配置方法及错误级别修改
    本文介绍了在mac环境下配置php错误日志的方法,包括修改php.ini文件和httpd.conf文件的操作步骤。同时还介绍了如何修改错误级别,以及相应的错误级别参考链接。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
author-avatar
哈喽随风amy
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有