C++的异常安全隐式生成赋值运算符

Mr.*_*C64 15 c++ exception assignment-operator exception-safety

我的理解是C++ 隐式生成的赋值运算符执行成员方式的复制(这似乎也得到了这个答案的证实).但是,如果在成员副本期间抛出异常(例如,因为无法分配该成员的资源),被复制的对象是否会陷入无效状态?

换句话说,隐式生成的赋值运算符是仅实现基本保证,而不是强保证?

如果我们想要为我们的类副本提供强有力的保证,我们是否必须使用copy-and-swap惯用法手动实现赋值运算符?

Ste*_*sop 11

如果您想提供异常保证,并且默认赋值运算符不是非常规,那么通常需要编写一个.

默认的拷贝分配不一定能达到基本保证,即不泄漏资源并保留类不变量.分配一些数据成员但不是全部可能会使目标处于不满足类不变量的状态,具体取决于特定的类.

所以你必须评估你的类的默认运算符 - 如果它可以抛出,并且通过抛弃对象处于"无效"状态,那么你必须抑制它.或者削弱已定义的类不变量,但这对用户没有多大帮助.

有(至少)一个特例.如果除了一个数据成员之外的所有数据成员都没有进行赋值,并且特殊成员具有强异常安全赋值,并且是该类中的第一个数据成员,那么默认赋值运算符也将是非常安全的.如果你依赖它,你可能会非常谨慎地评论,但它可能会非常脆弱!

  • 在一些非常简单的课程中,基本保证可以"偶然"实现.但是如果你的类满足这个要求,你需要记录为什么隐式生成的赋值运算符足够,这与编写自定义运算符的工作量大致相同.你至少需要考虑它. (3认同)
  • @ Mr.C64:复制和交换提供强有力的保证,前提是交换不是.证明很简单:交换之前没有对象被修改,只在交换之前抛出异常,因此抛出异常时不会修改任何内容.交换是强安全的就足够了,但通常你会因为其他原因而不想交换.主要的一点是,如果你需要进行*两次*交换并且每种都是非常安全的,那么并不意味着组合的操作是非常安全的.但是两个nothrow ops确实加起来了. (2认同)