swap には無送出保証の例外安全性が必要

『代入演算子の定石』では、swap には無送出保証の例外安全性が必要だと書いた。これに対して、「これなら原子性保証だけで十分なのでは?」という疑問が湧くかもしれない。ちなみに、こういうコード:

some_class& operator = (const some_class& another)
{
    some_class tmp_(another);
    swap(tmp_);

    return *this;
}

確かに、swap が例外を投げても (原子性保証があれば) 問題はないように見える。
実は、swap の無送出保証を要請しているのはこの代入演算子ではない。これは、このクラスをメンバ変数に持ったり継承したりするクラスが例外安全な swap を持つためのものだ。
たとえば、以下のようなクラスの swap の実装を見るとこれが分かる。

class enclosing_class
{
public:

    void swap(enclosing_class& another)
    {
        m_someValue.swap(another.m_someValue);
        m_anotherValue.swap(another.m_anotherValue);
    }

private:

    some_class    m_someValue;
    another_class m_anotherValue;

};

この enclosing_class:swap に原子性保証を与えるためには、some_class::swapanother_class::swap に無送出保証が必要になる。
まとめると:

  • 代入演算子は、原子性保証の例外安全性を備えるべき。
  • そのような代入演算子の実装には、(少なくとも原子性保証の) 例外安全性を持つ swap が必要になる。
  • 原子性保証の例外安全性を備えた swap は、基底クラスやメンバ変数が無送出保証の例外安全性を備えた swap を提供していなければ実装できない。
  • よって、いずれのクラスにあっても、swap は例外を送出してはならない。