【问题标题】:c++ assignment operator exception safetyc++ 赋值运算符异常安全
【发布时间】:2015-07-16 16:44:33
【问题描述】:

非常直接的问题:

要求赋值运算符不能抛出异常的原因是什么?

同时,构造函数可以抛出吗?


如果你不能抛出异常,如果没有足够的内存用于缓冲区分配,如何处理众所周知的“自定义”字符串示例?

如果你只是分配更少或保持旧状态,但不抛出异常,一切都会“看起来”顺利,但会出现严重(隐藏)错误。

【问题讨论】:

  • C++中没有这样的通用要求。
  • 嗯。好的,但为什么每个人都强调这一点?
  • 因为你不知道被分配的对象在异常之后保持什么状态?作业前的状态?分配后的状态?
  • 一两句话会有所帮助。
  • @n.m.没错,我的观点是我的个人观点,但是,由于赋值运算符是在可能的情况下自动生成的,所以调用者不知道 throw 语义,而在调用函数时他知道。那只是我的两分钱:)

标签: c++ c++11 exception assignment-operator


【解决方案1】:

绝对没有这样的要求。抛出一个任务是完全可以的。在许多情况下,抛出是不可避免的(例如,当赋值必须分配一些内存并且没有剩余时)。

赋值永远不应该让对象处于未定义状态。它必须要么成功地分配一个新值,要么让对象保持其原始状态(或者可能是其他一些不太理想的有效状态)并抛出。

这种语义通常由复制和交换习语实现。复制阶段可以扔。这使受让人完好无损。交换阶段绝不能抛出。

【讨论】:

  • 希望赋值运算符不抛出的一个可能原因是构造函数和赋值运算符的非抛出性“泄漏”到包含这些对象的容器。有一个类型特征 is_nothrow_move_assignable 显然是可取的
  • @MattMcNabb 移动不是复制。复制可以扔,移动不应该。
  • 移动分配是一种分配,OP并没有专门询问复制分配。实际上,您提到的复制和交换习语的通常实现提供了移动分配。
  • OP 询问所有作业。复制和交换提供了首要的复制分配。这是在移动操作发明之前很久的年代。如果复制构造函数抛出,它将抛出(正如我们所看到的那样)。您可以使用此成语进行移动分配,但它也会抛出。只需交换即可完成移动分配,无需复制。
  • 在使用相同的代码进行移动赋值时,我们仍然称其为“复制和交换”,即使它是移动而不是复制
猜你喜欢
  • 2012-10-31
  • 1970-01-01
  • 1970-01-01
  • 2011-07-29
  • 1970-01-01
  • 2021-08-10
  • 1970-01-01
  • 1970-01-01
  • 2016-04-01
相关资源
最近更新 更多