2012-03-28 2 views
2

Сильная гарантия безопасности исключений говорит о том, что операция не изменит какое-либо состояние программы, если возникает исключение. Элегантным способом реализации исключения для копирования является copy-and-swap idiom.C++ исключение безопасность паранойя: сколько слишком много?

Моих вопросов:

  1. было бы излишество использовать копирование и замены для каждой мутагенной работы класса, который мутирует непримитивные тип?

  2. Является ли производительность действительно справедливой торговлей для сильного исключения-безопасности?

. Например:

class A 
{ 
    public: 
     void increment() 
     { 
      // Copy 
      A tmp(*this); 

      // Perform throwing operations on the copy 
      ++(tmp.x); 
      tmp.x.crazyStuff(); 

      // Now that the operation is done sans exceptions, 
      // change program state 
      swap(tmp); 
     } 

     int setSomeProperty(int q) 
     { 
      A tmp(*this); 
      tmp.y.setProperty("q", q); 
      int rc = tmp.x.otherCrazyStuff(); 
      swap(tmp); 
      return rc; 
     } 

     // 
     // And many others similarly 
     // 

     void swap(const A &a) 
     { 
      // Non-throwing swap 
     } 

    private: 
     SomeClass x; 
     OtherClass y; 
}; 
+1

Ответ зависит в значительной степени от вашего домена, и на него нельзя ответить за его пределами. Если от этого зависит жизнь, ответ очевиден: он достоин штрафа за исполнение. Если код обработки исключений уничтожит ваш объект в случае исключения, это не имеет значения. Теперь вам нужно найти, где в середине лежит ваш код. –

+0

Если вы правильно определяете свой код в компонентах с одной ответственностью, вы часто получаете много исключений безопасности «бесплатно». В вашем примере, почему функция «increment» делает «сумасшедшие вещи»? Либо инкрементный алгоритм является сложным, но и знает, как выполнить вычисление транзакционно, или вам нужно отделить приращение и crazystuffing. –

+0

Ну, вы можете использовать ту же идею и просто применить ее к членам. Не нужно быть всем этим. Что сказать, если ваш класс содержит вектор строк, и вам нужно только его изменить? Не копируйте и не меняйте весь класс, вектор и все. Просто сделайте это на одной строке. – BoBTFish

ответ

1

Как и все вопросы техники, речь идет о балансе.

Конечно, const -ness/неизменность и надежные гарантии повышают уверенность в своем коде (особенно в сочетании с испытаниями). Они также помогают сократить количество возможных объяснений ошибки.

Однако они могут повлиять на производительность.

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

1

Это зависит от того, в какой среде приложение будет работать в случае, если вы просто запустить его на своей машине (один конец спектра), он не может стоит быть слишком строгим в отношении безопасности исключений. Если вы пишете программу, например. для медицинских устройств (на другом конце), вы не хотите, чтобы непреднамеренные побочные эффекты остались позади, когда возникает исключение. Все, что находится между ними, зависит от уровня допуска к ошибкам и доступных ресурсов для разработки (время, деньги и т. Д.)

3

Вы всегда должны стремиться к основной гарантии исключения: убедитесь, что в случае исключения, все ресурсы освобождаются правильно, и объект находится в допустимом состоянии (которое может быть неопределенным, но действительным).

Сильная гарантия исключения (т. Е. «Транзакции») - это то, что вы должны реализовать, когда считаете, что это имеет смысл: вам не всегда требуется транзакционное поведение.

Если легко осуществить транзакционные операции (например, с помощью копии & swap), то сделайте это. Но иногда это не так, или это наносит большой эффект, даже для фундаментальных вещей, таких как операции присваивания. Я помню, что реализовал что-то вроде boost :: variant, где я не всегда мог обеспечить сильную гарантию при назначении копии.

С огромной трудностью вы столкнетесь с семантикой перемещения. Вы do хотите совершать транзакции при перемещении, потому что в противном случае вы потеряете перемещенный объект. Однако вы не всегда можете обеспечить надежную гарантию: подумайте о std::pair<movable_nothrow, copyable> (и посмотрите комментарии). Здесь вы должны стать виртуозом noexcept и использовать неудобное количество метапрограммирования. C++ трудно овладеть точно из-за исключения безопасности.

+0

В чем проблема с 'std :: pair '? Как вы говорите, трудно написать 'pair', так что все операции nohrow либо выполняются последними, либо (что еще хуже) отменены при выполнении операции non-nothrow. Но в случае одного nothrow op и того, который сам предлагает сильную гарантию исключения, существует правильная последовательность операций. –

+0

@SteveJessop: Да, хорошая точка. Однако конструктор перемещения 'std :: pair' не будет' noexcept'. Кроме того, такой подход делает мою точку зрения: безопасность исключений сложна, и для перемещения семантики требуется много метапрограммирования шаблона Фу. Как вы напишете конструктор перемещения 'std :: pair ' (обратите внимание на изменение аргументов)? Вы хотите построить 'second' перед' first', но для этого требуется, чтобы они были объявлены в этом порядке. –

0

Да, проблема, с которой вы сталкиваетесь, заключается в том, что эту идиому очень сложно масштабировать. Ни один из других ответов не упомянул об этом, но еще один очень интересный идиом, изобретенный Александреску под названием scopeGuards. Это помогает повысить экономичность кода и значительно улучшает читаемость функций, которые должны соответствовать сильным гарантиям безопасности исключений.

Идея защиты области видимости - это экземпляр стека, который позволяет просто прикреплять объекты функции отката к каждому ресурсовому объявлению. когда ограждение области видимости уничтожается (за исключением), вызывается откат. Вы должны явно вызвать commit() в нормальном потоке, чтобы избежать вызова отката при выходе из области действия.

Отметьте this recent question from me, что связано с созданной безопасной скопперой с использованием возможностей C++ 11.