C ++ исключение паранойя безопасности: сколько это слишком много? - PullRequest
2 голосов
/ 28 марта 2012

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

Мои вопросы:

  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;
};

Ответы [ 4 ]

3 голосов
/ 28 марта 2012

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

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

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

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

2 голосов
/ 28 марта 2012

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

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

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

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

1 голос
/ 28 марта 2012

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

0 голосов
/ 23 апреля 2012

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

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

Отметьте этот недавний вопрос от меня , связанный с разработкой безопасной прицельной охраны с использованием функций c ++ 11.

...