Подтвердить что ты не робот

Статический анализ noexcept "нарушений" в С++

Я пытаюсь написать безопасный код исключения. Я считаю, что использование спецификатора noexcept С++ 11 делает эту цель намного более достижимой.

Общая идея, конечно, состоит в том, что функция должна быть помечена как "noexcept", если и только если все функции, которые она вызывает, также отмечены как "noexcept".

Проблема заключается в том, что в большой базе кода, где исправления от разных людей часто объединяются вместе, трудно гарантировать, что эта согласованность сохраняется.

Итак, я хотел бы иметь возможность запускать статический анализ, который мог бы отображать все места, где функция, отмеченная "nothrow", вызывает функцию, которая не помечена как "nothrow".

Насколько я могу видеть на man-странице, GCC мне не поможет. Существуют ли какие-либо автономные инструменты, которые могут мне помочь? Или, может быть, некоторые другие компиляторы?

4b9b3361

Ответ 1

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

С другой стороны, я задаюсь вопросом, насколько это практично. Видите ли, проблема в том, что любая функция, выполняющая выделение памяти (по-доброму), помечена как потенциально метать (потому что new никогда не возвращает значение null, а вместо этого бросает 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.