Метод сильной гарантии, вызывающий методы сильной гарантии - PullRequest
3 голосов
/ 20 сентября 2010

Когда у меня есть метод, который вызывает набор методов, которые предлагают сильную гарантию, у меня часто возникает проблема с откатом изменений, чтобы также иметь метод сильной гарантии. Давайте использовать пример:

// Would like this to offer strong guarantee
void MacroMethod() throw(...)
{
  int i = 0;
  try
  {
    for(i = 0; i < 100; ++i)
       SetMethod(i); // this might throw
  }
  catch(const std::exception& _e)
  {
    // Undo changes that were done
    for(int j = i; j >= 0; --j)
      UnsetMethod(j); // this might throw
    throw;
  }
}

// Offers strong guarantee
void SetMethod(int i) throw(...)
{
  // Does a change on member i
}

// Offers strong guarantee
void UnsetMethod() throw(...)
{
  // Undoes a change on member i
}

Очевидно, что UnsetMethod может бросить. В этом случае мой MacroMathod () предлагает только базовую гарантию. Тем не менее, я сделал все, что мог, чтобы предложить надежную гарантию, но я не могу быть абсолютно уверен, что мой UnsetMethod () не сработает. Вот мои вопросы:

  1. Стоит ли даже пытаться предложить надежную гарантию в этом случае?
  2. Должен ли я документировать свой MacroMethod () как имеющий базовую или надежную гарантию? Даже если это очень маловероятно, UnsetMethod выбросит?
  3. Можете ли вы найти способ сделать этот метод действительно надежной гарантией?
  4. Вероятно, мне следует попытаться выполнить вызов UnsetMethod (), но это довольно тяжело, и что мне делать в улове?

Спасибо!

Ответы [ 4 ]

6 голосов
/ 20 сентября 2010

Хороший шаблон для достижения этой цели - заставить ваш метод работать с копией объекта, который вы хотите изменить. Когда все изменения сделаны, вы меняете объекты (своп должен быть гарантированно не брошен). Это имеет смысл, только если копирование и обмен могут быть реализованы эффективно.

Этот метод имеет то преимущество, что вам не нужны никакие try...catch -блоки в вашем коде, а также нет кода очистки. Если выдается исключение, измененная копия сбрасывается при разматывании стека, а оригинал вообще не изменяется.

1 голос
/ 20 сентября 2010
  1. Нет, вы не можете вообще с кодом, который вы дали. Однако, в зависимости от вашей проблемы, возможно, вы можете сделать копию данных, выполнить SetMethod для этой копии и затем поменять местами представление. Это дает надежную гарантию, но опять же зависит от проблемы.
  2. Вы можете задокументировать: Сильная гарантия, если UnsetMethod не генерирует, в противном случае - базовая. На самом деле это объясняет, почему говорят, что деструкторы не должны бросать. На самом деле любые операции отмены не должны выбрасывать.
  3. Да, см. 1.
  4. Нет, это не имеет смысла.
1 голос
/ 20 сентября 2010

Если для MacroMethod() важна гарантия сильного исключения, я бы изменил UnsetMethod(), чтобы вообще ничего не бросать, если вы можете. Конечно, как это можно сделать, зависит от того, что вы делаете.

Вы используете UnsetMethod() для очистки после сбоя с SetMethod(). Если UnsetMethod() не удается очистить, что вы можете с этим поделать? По той же причине выбрасывать исключения из деструкторов крайне опасно.

0 голосов
/ 20 сентября 2010

По сути, что вам нужно сделать в функциях, которые вызывают функции выброса, так это работать с временной копией данных до тех пор, пока не завершатся все возможные функции выброса, затем swap (которая не должна выбрасывать) временные значенияв «реальную» структуру.

Некоторый иллюстративный псевдокод:

void MacroMethod() throw(...)
{
  int i = 0;
  MyValues working_copy[100] = *this;  //obviously this is psudocode as I don't know your real code
  for(i = 0; i < 100; ++i)
     working_vopy[i].SetMethod(i); // if this throws the exception will propogate out, and no changes will be made
  swap( *this, working_copy);  // this must not throw
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...