Я пытаюсь написать безопасный код исключения. Я считаю, что использование спецификатора noexcept в C ++ 11 делает эту цель намного более достижимой.
Общая идея, конечно же, заключается в том, что функция должна быть помечена как noexcept, если и только если все вызываемые ею функции также помечены как noexcept.
Проблема заключается в том, что в большой кодовой базе, где исправления от разных людей часто объединяются, трудно обеспечить сохранение этой согласованности.
Поэтому я хотел бы иметь возможность запустить статический анализ, в котором можно было бы перечислить все места, где функция, помеченная как nothrow, вызывает функцию, которая не помечена как nothrow.
Насколько я вижу на странице руководства, GCC не может помочь мне здесь. Существуют ли какие-либо автономные инструменты, которые могут мне помочь? Или, может быть, некоторые другие компиляторы?
Это, конечно, кажется возможным, если вы избегаете указателя на функции (и считаете их небезопасными), используя ABT программы. AST от Clang (несмотря на название) такой ABT: вы увидите как объявления, так и определения функций. Выполняя свою работу по одному определению за раз, у вас уже будет хороший базовый уровень.
С другой стороны, мне интересно, практическое. Видите, проблема в том, что любая функция, выполняющая выделение памяти, (добровольно) помечается как потенциально выбрасываемая (потому что new
никогда не возвращает ноль, но бросает bad_alloc
вместо). Поэтому ваш noexcept
будет ограничено несколькими функциями в большинстве случаев.
И, конечно, есть все динамические условия, такие как @GManNickG, например:
void foo(boost::optional<T> const t&) {
if (not t) { return; }
t->bar();
}
Даже если T::bar
является noexcept
разыменование optional<T>
может скинуть (если ничего нет). Конечно, это игнорирует тот факт, что мы уже исключили это (здесь).
Не имея ясно условия когда функция может throw
, static
анализ может оказаться … бесполезным. Языковые идиомы разработаны с учетом исключений.
Примечание: в качестве отступления необязательный класс может быть переписан так, чтобы не подвергаться разыменованию, и поэтому noexcept
(если обратные вызовы есть):
template <typename T>
class maybe {
public:
template <typename OnNone, typename OnJust>
void act(OnNone&& n, OnJust&& j) noexcept(noexcept(n()) and
noexcept(j(std::declval<T&>())))
{
if (not _assigned) { n(); return; }
j(*reinterpret_cast<T*>(&_storage));
}
private:
std::aligned_storage<sizeof(T), alignof(T)>::type _storage;
bool _assigned;
};
// No idea if this way of expressing the noexcept dependency is actually correct.
Других решений пока нет …