Как реализовать strong exception safety push?

У меня есть класс - циклический буфер, который при push-е кладёт элемент на нужное место, при этом, если буфер полон, то он затирает один элемент и кладёт туда новый элемент, вот как реализовано у меня

  void Angry_Put(size_t last_pos, const T& value, size_t new_value) {
    T old_value = data_[last_pos];
    data_[last_pos].~T();
    try {
      new (&data_[last_pos]) T(value);
    } catch (...) {
      new (&data_[last_pos]) T(old_value);
      throw;
    }
    head = new_value;
  }

Как бы выглядел бы код, со strong exception safety если

  1. Конструкторы могут кидать исключения
  2. Оператор копирования может кидать исключение (его может и не быть)
  3. Может быть такое, что объект кидает исключение через время (поэтому если допустим в начале его положили куда то, а потом вновь переложили обратно, то тут тоже может вылететь исключение)
  4. Важно, что тут именно, что надо придумать решение без move-семантики

Ответы (1 шт):

Автор решения: Stanislav Volodarskiy

std::swap обычно гарантирует отсутствие изменений при неуспехе. Положимся на на него:

  void Angry_Put(size_t last_pos, const T& value, size_t new_value) {
    using std::swap;

    T copy = value;
    swap(data_[last_pos], copy);
    head = new_value;
  }

Ещё имеет смысл перенести копирование в вызов функции:

  void Angry_Put(size_t last_pos, T value, size_t new_value) {
    using std::swap;

    swap(data_[last_pos], value);
    head = new_value;
  }

P.S. Кстати сказать std::swap вводился как средство обеспечения "strong exception safety" и оптимизация задолго до появления в языке семантики перемещения.

→ Ссылка