异常保证和按值传递

2024-03-21

我最近在多种情况下遇到过这个问题,其中表达的一些观点让我感到惊讶。这是第一个简单的例子:

void f(std::vector<double> x) {};

问题是:记录或描述是否可以接受f作为提供不抛出保证?同样,我怀疑由于异常不是从 f 的主体生成的,因此使用noexcept从技术上来说是干净的。但应该标记一下吗noexcept?一个例子是,例如,优化版本set以某种方式发现添加模板化比较器不得抛出的要求很有用。它在编译时使用静态断言检测到这一点并导致错误。然而,有人可以为按值获取的向量编写一个比较器,并将其标记为 noexcept,并将其与此版本的set。如果这导致了不良行为,那么这是容器作者的错吗?或者将比较器标记为 no except 的人?

再举一个涉及另一种异常保证类型的示例,请考虑:

void g(std::vector<double> x, std::unique_ptr<int> y);

该功能能否提供强有力的保证?

std::vector<double> p{1.0, 2.0};
auto q = std::make_unique<int>(0);
bool func_successful = true;

try {
  g(p, std::move(q));
}
catch (...) {
  func_successful = false;
}

if (!func_successful)
  assert(q);

我认为,如果断言可能失败,那么 g 不会提供强有力的保证,因为q在调用 g 之前不为空(记住std::move实际上并没有移动任何东西)。它可能会失败:参数评估的顺序未指定,因此可能首先构造 y 清空 q,然后构造 x 并抛出。即使从技术上讲它不是发生在函数体中,而是发生在调用函数的行为中,该函数仍然对此负责吗?

编辑:我要提到赫伯·萨特在这里谈论这个问题:https://youtu.be/xnqTKD8uD64?t=1h11m56s https://youtu.be/xnqTKD8uD64?t=1h11m56s。他说,将这样的函数标记为 noexcept 是“有问题的”;我希望得到更详细的答复。


标准(5.2.2 函数调用 [expr.call] §4)规定参数初始化和销毁​​发生在调用函数的上下文中。所以是的,它is从技术上讲是洁净的声明f as noexcept.

尽管一开始是违反直觉的,但它确实有道理。f可以使用右值调用,在这种情况下,将使用 move-ctor 来初始化参数,因此即使调用函数的整个构造(包括参数设置和拆卸)仍然会是noexcept. Or f可以用空向量调用,在这种情况下,整个构造仍然会有效地 be noexcept- 至少是我认为“合理”的库实现。

还要考虑带有 const-ref 参数的函数:

void x(std::string const&) noexcept {}

void y() noexcept
{
    x("foo");
}

x is noexcept好的。来电y然而不是,因为它包含一个(可能抛出)隐式转换。所以如果声明f as noexcept风格很糟糕,难道不应该这样说吗x?

所以我认为C++程序员应该做两件事之一:不使用和不依赖noexcept规范,或内化规则,并始终对他们在呼叫站点所做的事情感到厌倦。


关于第二个问题(强保证)... 我想说一个函数永远不能声明论点它被称为与。而且它永远不能对它的未来发生的事情做出声明参数如果它从未被真正调用过。

如果您心目中的强有力的保证包括此类声明,那么我同意该功能不能提供这种强有力的保证。

尽管我不一定同意强有力的保证——对于具有这样的签名的函数——应该包括这样的声明。 我什么would说的是:if这种声明对于强有力的保证具有任何实际意义是必要的,那么该函数不应该使用按值参数。

OTOH,如果这样的主张对于强有力的保证具有实际意义来说不是必要的,那么我认为我没有理由“禁止”它。例如。

void StrongAppendAll(std::vector<T>& a, std::vector<T> b);

IMO对该功能的“自然”有力保证是它要么附加所有元素b to a,或者,如果抛出异常,则离开a不变。我绝不会假设该保证包括任何有关所发生情况的索赔b。更不用说关于用于初始化的任何参数会发生什么的任何声明b.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

异常保证和按值传递 的相关文章

  • 采用 std::vector 或 std::array 的模板函数

    我有一个函数 当前接受 2 个向量 其中可以包含任何普通的旧数据 template
  • 如何使用 Entity Framework 和 Identity 解决对象处置异常 ASP.NET Core

    我正在尝试编写一个控制器 该控制器接收来自 AJAX 调用的请求并通过 DBContext 对数据库执行一些调用 但是 当我发出命令时var user await GetCurrentUserAsynch 在对 DBContext 的任何调
  • 更新 Azure Blob 上的 LastModified

    我正在移植代码以使用 C 中的 Azure 存储 SDK 传统上 我称其为更新修改文件的上次写入 修改时间 File SetLastWriteTimeUtc fileName lastWriteTimeUtc 要更新 blob 的上次修改时
  • 如何通过覆盖 MSBuild 目标来防止外语资源生成?

    我正在致力于减少大型 C ASP NET 解决方案的编译时间 我们的解决方案使用通常的 resx 文件方法翻译成大约十几种外语 这些资源文件的解析和编译极大地减慢了我们的编译时间 并且是日常的挫败感 我知道可以创建自定义资源提供程序并摆脱
  • 信号与信号2

    我的应用程序可能会受益于使用 boost 的信号库之一而不是本土解决方案 该应用程序是多线程的 但执行信号处理的部分是单线程的 如果多线程不是问题 是否有任何理由更喜欢 Boost Signals2 而不是 Boost Signal Boo
  • 头文件中实现的函数的静态与内联

    我想到的方式inline在 C 中用于链接 作用域 我把它放在同一个篮子里extern and static对于全局对象 通常 对于在头文件中实现的函数 我的首选解决方案是将其设为静态 In Foo h static void foo Do
  • 如何在 C++ 和 QML 应用程序中使用 qrc?

    我在 Windows7 上用 c qnd Qt Creator QML 编写了 Qt Quick Desktop 应用程序 现在 我必须部署它 并且我需要隐藏 qml 文件和图像 意味着 将它们放入资源等中 我读到有一个很好的方法可以使用
  • 列表到优先队列

    我有一个 C 大学编程项目 分为两个部分 在开始第二部分时应该使用priority queues hash tables and BST s 我 至少 在优先级队列方面遇到了麻烦 因为它迫使我自己重做第一部分中已经实现的许多代码 该项目是关
  • 如果finally 块包含await,为什么*有时*不会在ThreadAbortException 上执行?

    UPDATE 我不认为这个问题是重复的ThreadAbortException最后可以跳过吗 https stackoverflow com questions 18002668 can threadabortexception skip
  • 使用 cmake 将两种解决方案合二为一

    我有两个单独的 Visual Studio 2013 解决方案 我想将它们迁移到一个解决方案中 因为第一个解决方案 使用 Qt 充当第二个解决方案的 GUI 最后 我希望有一个结构如下的单一解决方案 Solution All Build P
  • 应在堆栈上分配的最大数量

    我一直在寻找堆栈溢出有关应在堆栈上分配的最大内存量的指南 我看到了堆栈与堆分配的最佳实践 但没有关于应该在堆栈上分配多少以及应该在堆上分配多少的指南 有什么想法 数字可以作为指导吗 什么时候应该在堆栈上分配 什么时候应该在堆上分配 多少才算
  • 在 C# 命令行应用程序中包含并执行 EXE

    所以我找到了一个很棒的小 EXE 命令行应用程序 我们将其称为 program exe 它输出一些我想用 C 操作的数据 我想知道是否有一种方法可以将program exe 打包 到我的Visual Studio项目文件中 这样我就可以将编
  • 调试错误:在 vc++ 项目中使用 COM 时发生 所需的运行时?

    我为我的工作创建了一个 COM 组件 我也注册了该组件 在我的系统上 我有两个虚拟机工作站 在我的第一个工作站中 它运行良好 在我的第二个工作站中 它显示一个包含消息的错误框该程序需要一段时间并以不寻常的方式关闭 请联系应用程序管理员 我认
  • 实体框架读取列但阻止其更新

    给定一个数据库表 其中有一列包含历史数据但不再填充 实体框架中是否有一种方法可以读取该列 但在使用相同的模型对象时防止它被更新 例如我有一个对象 public class MyObject public string CurrentData
  • 展开 std::reference_wrapper 的成本

    Given include
  • 如何通过代理将套接字连接到http服务器?

    最近 我使用 C 语言编写了一个程序 用于连接到本地运行的 HTTP 服务器 从而向该服务器发出请求 这对我来说效果很好 之后 我尝试使用相同的代码连接到网络上的另一台服务器 例如 www google com 但我无法连接并从网络中的代理
  • 为什么 C++ 标准没有将 sizeof(bool) 定义为 1?

    Size of char signed char and unsigned char由 C 标准本身定义为 1 个字节 我想知道为什么它没有定义sizeof bool also C 03 标准 5 3 3 1 说 sizeof char s
  • 使用任务的经典永无止境的线程循环?

    给出了一个非常常见的线程场景 宣言 private Thread thread private bool isRunning false Start thread new Thread gt NeverEndingProc thread S
  • 在 C# 中使用自定义千位分隔符

    在显示字符串时 我尝试不使用 字符作为千位分隔符 而是使用空格 我想我需要定义一种自定义文化 但我似乎做得不对 有什么指点吗 例如 将 1000000 显示为 1 000 000 而不是 1 000 000 no String Replac
  • 在 LP2844Z(Zebra 打印机)上的收据中包含 PNG [重复]

    这个问题在这里已经有答案了 我正在致力于创建一个基于 HTML5 画布的签名 绘图框 目前我们在服务器上将画布保存为PNG 但可以轻松地将base64字符串保存在数据库中 现在的问题是我们如何在打印的收据上添加签名 目前我们使用 GF 字段

随机推荐