为什么 C++ 标准文件流没有更严格地遵循 RAII 约定?

2024-01-01

为什么 C++ 标准库使用流open()/close()语义与对象生命周期分离?从技术上讲,关闭销毁可能仍会生成类 RAII,但获取/释放独立性会在范围内留下漏洞,其中句柄可以指向任何内容,但仍需要运行时检查来捕获。

为什么库设计者选择他们的方法而不是仅在引发失败的构造函数中打开?

void foo() {
  std::ofstream ofs;
  ofs << "Can't do this!\n"; // XXX
  ofs.open("foo.txt");

  // Safe access requires explicit checking after open().
  if (ofs) {
    // Other calls still need checks but must be shielded by an initial one.
  }

  ofs.close();
  ofs << "Whoops!\n"; // XXX
}

// This approach would seem better IMO:
void bar() {
  std_raii::ofstream ofs("foo.txt"); // throw on failure and catch wherever
  // do whatever, then close ofs on destruction ...
}

这个问题的更好措辞可能是为什么访问非开放的fstream永远值得拥有。在我看来,通过句柄生命周期控制打开文件的持续时间根本不是一种负担,但实际上是一种安全优势。


尽管其他答案是有效且有用的,但我认为real原因更简单。

iostreams 的设计比许多标准库要古老得多,并且早于异常的广泛使用。我怀疑为了与现有代码兼容,异常的使用是可选的,而不是打开文件失败的默认值。

另外,您的问题仅与文件流真正相关,其他类型的标准流没有open() or close()成员函数,因此如果无法打开文件,它们的构造函数不会抛出异常:-)

对于文件,您可能需要检查close()调用成功,因此您知道数据是否已写入磁盘,这是一个很好的理由not在析构函数中执行此操作,因为当对象被销毁时,已经太晚了,无法对其执行任何有用的操作,并且您几乎肯定不想从析构函数中抛出异常。所以一个fstreambuf将在其析构函数中调用 close,但如果您愿意,您也可以在销毁之前手动执行此操作。

无论如何,我不同意它不遵循 RAII 约定......

为什么库设计者选择他们的方法而不是仅在引发失败的构造函数中打开?

注意: RAII 并不代表你can't有一个单独的open()除了获取资源的构造函数之外的成员,或者您can't在销毁之前清理资源,例如unique_ptr has a reset() member.

另外,RAII并不意味着你must失败时抛出,或者抛出一个对象can't处于空状态,例如unique_ptr可以使用空指针或默认构造来构造,因此也可以指向任何内容,因此在某些情况下您需要在取消引用之前检查它。

文件流在构建时获取资源并在销毁时释放它 - 就我而言,这就是 RAII。您反对的是需要进行检查,这有两阶段初始化的味道,我同意这有点臭。但这并不意味着它不是 RAII。

过去我用过一种方法来解决气味CheckedFstream类,这是一个简单的包装器,添加了一个功能:抛出无法打开流的构造函数。在 C++11 中,就这么简单:

struct CheckedFstream : std::fstream
{
  CheckedFstream() = default;

  CheckedFstream(std::string const& path, std::ios::openmode m = std::ios::in|std::ios::out)
  : fstream(path, m)
  { if (!is_open()) throw std::ios::failure("Could not open " + path); }
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 C++ 标准文件流没有更严格地遵循 RAII 约定? 的相关文章

  • 在 C/C++ 中获得正模数的最快方法

    通常在我的内部循环中 我需要以 环绕 方式索引数组 因此 例如 如果数组大小为 100 并且我的代码要求元素 2 则应该给它元素 98 高级语言 例如 Python 可以简单地使用my array index array size 但由于某
  • QCombobox 向下箭头图像

    如何更改Qcombobox向下箭头图像 现在我正在使用这个 QSS 代码 但这不起作用 我无法删除向下箭头边框 QComboBox border 0px QComboBox down arrow border 0px background
  • 使用 Enumerable.OfType() 或 LINQ 查找特定类型的所有子控件

    Existed MyControl1 Controls OfType
  • ASP.NET Web API 客户端 ProgressMessageHandler Post 任务卡在 WinForm 应用程序中

    我在用着HttpClient and ProgressMessageHandler来自MS ASP NET Web API 客户端库 http nuget org packages Microsoft AspNet WebApi Clien
  • 如何在 SqlDataReader.Read() 期间从死锁异常中恢复

    我的 NET 应用程序的事件日志显示 它在从 Sql Server 读取数据时偶尔会出现死锁 这种情况通常非常罕见 因为我们已经优化了查询以避免死锁 但有时仍然会发生 过去 我们在调用ExecuteReader函数在我们的SqlComman
  • ASP.Net Core 内容配置附件/内联

    我正在从 WebAPI 控制器返回一个文件 Content Disposition 标头值自动设置为 附件 例如 处置 附件 文件名 30956 pdf 文件名 UTF 8 30956 pdf 当它设置为附件时 浏览器将要求保存文件而不是打
  • fprintf() 线程安全吗?

    我正在为野人就餐问题的某些变量编写一个 C 解决方案 现在 我创建线程 每个线程都将 FILE 获取到同一个调试文件 在线程内我正在使用 fprintf 进行一些打印 打印的语句不受任何类型的互斥锁等保护 我没有在调试文件中观察到任何交错行
  • vs2008 c#:Facebook.rest.api如何使用它来获取好友列表?

    如何在此基础上取得进一步的进步 获取好友列表的下一步是什么 string APIKey ConfigurationManager AppSettings API Key string APISecret ConfigurationManag
  • Visual Studio Code:如何配置 includePath 以获得更好的 IntelliSense 结果

    我是使用 Visual Studio Code 的完全初学者 我不知道我在做什么 我已经四处搜索 也许还不够 但我找不到像我这样的人如何配置的简单解释c cpp properties json每当我单击带有绿色波浪线下划线的行旁边的黄色灯泡
  • C++ php 和静态库

    我创建了一个library a 其中包含 cpp 和 h 文件 其中包含很多类 嵌套类和方法 我想在 php 示例中包含这个静态库并尝试使用它 我想提一下 我是 php 新手 我已经在 test cpp 文件中测试了我的 libray a
  • 每个租户的唯一用户名和电子邮件

    我正在使用以下代码编写多租户应用程序ASP NET Core 2 1 我想覆盖默认的与用户创建相关的验证机制 目前我无法创建多个具有相同的用户UserName My ApplicationUser模型有一个名为TenantID 我想要实现的
  • 在 EnvDTE 中调试时捕获 VS 局部变量

    是否可以使用 EnvDTE 进行 vsix Visual Studio 扩展来捕获本地和调试窗口使用的调试数据 或者可以通过其他方法吗 我想创建一个自定义的本地窗口 我们可以修改它以根据需要显示一些较重的内容 而无需为高级用户牺牲原始的本地
  • .NET Core 中的跨平台文件名处理

    如何处理文件名System IO以跨平台方式运行类以使其在 Windows 和 Linux 上运行 例如 我编写的代码在 Windows 上完美运行 但它不会在 Ubuntu Linux 上创建文件 var tempFilename Dat
  • IEnumerable.Except 不起作用,那么我该怎么办?

    我有一个 linq to sql 数据库 非常简单 我们有 3 个表 项目和用户 有一个名为 User Projects 的连接表将它们连接在一起 我已经有了一个获得的工作方法IEnumberable
  • 使用restsharp序列化对象并将其传递给WebApi而不是序列化列表

    我有一个看起来像的视图模型 public class StoreItemViewModel public Guid ItemId get set public List
  • cout 和字符串连接

    我刚刚复习了我的 C 我尝试这样做 include
  • 使用taskkill停止Windows服务

    我需要帮助来使用 C 终止 Windows 服务 现在要终止该服务 请使用以下选项 从命令 sc queryex ServiceName 发现后PID服务的 taskkill pid 1234 exemple f 为了便于阅读 但如果您明白
  • 您是否将信息添加到每个 .hpp/.cpp 文件的顶部? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 创建新的 C 头文件 源文件时 您会在顶部添加哪些信息 例如 您是否添加日期 您的姓名 文件描述等 您是否使用结构化格式来存储此信息 e g F
  • 在简单注入器中解析具有自定义参数的类

    我正在使用以下命令创建 WPF MVVM 应用程序简易注射器作为 DI 容器 现在 当我尝试从简单注入器解析视图时遇到一些问题 因为我需要在构造时将参数传递到构造函数中 而不是在将视图注册到容器时 因此这不是适用的 简单注入器将值传递到构造
  • Java 和/C++ 在多线程方面的差异

    我读过一些提示 多线程实现很大程度上取决于您正在使用的目标操作系统 操作系统最终提供了多线程能力 比如Linux有POSIX标准实现 而windows32有另一种方式 但我想知道编程语言水平的主要不同 C似乎为同步提供了更多选择 例如互斥锁

随机推荐

  • Semantic-ui 与 Bootstrap [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 哪一种最好用 如果可能 请提供这两者的区别和优点 语义用户界面 http semantic ui com vs 引导程序 http getboo
  • 将 Rails 应用程序部署到 Heroku 不断崩溃

    这个答案似乎已经以多种方式得到了回答 但似乎没有一个适合我的确切问题 我正在使用 RailsApps 中的应用程序https github com RailsApps rails devise pundit https github com
  • 如何将git存储库的根设置为vi/vim查找路径?

    我想设置 vim 文件搜索路径以包括 git 存储库根 可以通过以下方式找到 git rev parse show toplevel 我不知道如何附加这个输出git命令 set path 在 vimrc 中 Thanks 您可以使用此命令
  • 在从 XAML 实例化的控件中使用 MEF

    我创建了一个 UserControl 它使用 Import 属性 public class MyUserControl UserControl IPartImportsSatisfiedNotification Import public
  • 使用正确的派生类型调用泛型方法

    我有以下场景 我有三个课程 我们称它们为A B and C 它们的共同点是它们继承自相同的接口 ISomeInterface它们是使用实体框架映射到实体的类 我有一个方法接收实现此接口的对象列表 但对象本身将是A B or C 方法外壳看起
  • 网格碰撞器在应该有孔的地方有墙壁并且变形了

    我的曲线水管模型需要一个曲线圆柱对撞机 以便我的玩家红色立方体可以轻松通过 我尝试了网格碰撞器 它不起作用 还尝试了另一种技巧 我在搅拌机中构建了 2 个模型 一个用于网格渲染 一个用于碰撞器 作为一个整体 九分之一导致网格碰撞器无法在整个
  • Gtest:“{”之前预期的类名

    我正在尝试将 Gtest 下的测试用例转换为使用测试夹具 以便在添加更多测试时可以有一个通用的设置 然而 这会导致错误 test integrate cc 4 47 error expected class name before toke
  • 使用 perl 和 Net::DNS 检查 DNS

    所以 在 有一个小脚本 参见第 173 页 其目的是迭代检查 DNS 服务器以查看它们是否为给定主机名返回相同的地址 然而 书中给出的解决方案仅当主机具有静态IP地址时才有效 如果我希望该脚本能够与具有多个关联地址的主机一起使用 我该如何编
  • jquery 相当于 getcompulatedstyle()

    我在一个中找到了这个 getCompulatedStyle polyfillJavaScript 插件 https github com viljamis responsive nav js if computed window getCo
  • 为什么根文件系统被加载到ramdisk中?

    我正在研究Linux的启动过程 我遇到过这样一句话 RAM 比软盘快几个数量级 因此 ramdisk 的系统运行速度很快 无论如何 内核都会将根文件系统加载到 RAM 中来执行它 所以我的问题是 如果内核将根文件系统加载到 RAM 中 为什
  • Twig - 获取规范标签的 URL

    我希望在我的应用程序中创建一个动态 rel canonical 标签 该标签会拉入当前 URL 但希望确保删除所有查询参数 例如http www example com test page 2 http www example com te
  • 使用 karma 进行角度单元测试时,dispatchEvent() 和 triggerEventHandler() 有什么区别?

    我正在为指令 在输入事件上调用 编写单元测试 该指令正在修改 formControl 上的输入值 我在我的规范文件中创建了一个测试组件 我注意到triggerEventHandler 和dispatchEvent 之间的区别 在trigge
  • 对“__android_log_print”的未定义引用

    我的 make 文件有什么问题 Android mk LOCAL PATH call my dir include CLEAR VARS LOCAL MODULE foo LOCAL SRC FILES foo c LOCAL EXPORT
  • 使用流有条件地填充地图 - Java 8

    我正在尝试将此 简化的 代码转换为使用 Java 8 流 Map
  • XSLT Xalan dyn:评估示例

    我希望您在样式表中使用 EXSLT DYN EVALUATE 我已添加名称pace 但我不知道需要导入的 xsl 文件在哪里 我不相信我安装了 XALAN 来指向导入 我该如何安装这个 安装后 我将其指向 xsl 它会选择该函数并应用它吗
  • 显示表,描述 redshift 中等效的表

    我是 aws 新手 谁能告诉我 redshifts 与 mysql 命令的等价物是什么 show tables redshift command describe table name redshift command 所有信息都可以在PG
  • 生成随机、唯一的值 C#

    我已经搜索了一段时间并一直在努力找到这个 我试图用 C 生成几个随机的 唯一的数字 我在用着System Random 我正在使用DateTime Now Ticks seed public Random a new Random Date
  • R studio - 我需要使用混淆矩阵的敏感性和特异性以及阳性和阴性预测值的置信区间

    我正在写一篇关于住院儿童帐单代码有效性的论文 我是一个非常新手的 R studio 用户 我需要敏感性和特异性以及阳性和阴性预测值的置信区间 但我不知道该怎么做 我的数据有 3 列 ID true value billing value 这
  • Golang 模板“减号”功能

    我知道在go我可以调用名为的模板函数add对于像这样的表达1 1 但是如何为表达式命名函数2 1 没有add默认包含的功能 但是 您可以轻松地自己编写此类函数 例如 tmpl template Must template New Funcs
  • 为什么 C++ 标准文件流没有更严格地遵循 RAII 约定?

    为什么 C 标准库使用流open close 语义与对象生命周期分离 从技术上讲 关闭销毁可能仍会生成类 RAII 但获取 释放独立性会在范围内留下漏洞 其中句柄可以指向任何内容 但仍需要运行时检查来捕获 为什么库设计者选择他们的方法而不是