15

例外安全なコードを書こうとしています。C++11 の noexcept 指定子を使用すると、この目標がはるかに達成しやすくなることがわかりました。

もちろん、一般的な考え方は、関数が呼び出すすべての関数も「noexcept」としてマークされている場合にのみ、関数を「noexcept」としてマークする必要があるということです。

問題は、さまざまな人々からのパッチがマージされることが多い大規模なコード ベースでは、この一貫性を維持するのが難しいことです。

したがって、「nothrow」とマークされた関数が「nothrow」とマークされていない関数を呼び出すすべての場所をリストできる静的分析を実行できるようにしたいと考えています。

マンページを見る限り、GCC はここで私を助けることはできません。役立つスタンドアロン ツールはありますか? それとも他のコンパイラですか?

4

2 に答える 2

6

プログラムのABTを使用して、関数へのポインターを回避する(そしてそれらを安全でないと見なす)と、確かに可能と思われます。ClangのASTは(その名前にもかかわらず)そのようなABTです:関数の宣言と定義の両方が表示されます。一度に1つの定義で作業を行うことにより、すでに適切なベースラインが得られます。

一方で、これは実用的かと思います。問題は、メモリ割り当てを実行する関数が(自発的に)スロ​​ーする可能性があるとマークされていることです(newnullを返すことはなく、bad_alloc代わりにスローするため)。したがって、noexceptほとんどの場合、機能は少数に制限されます。

そしてもちろん、@ GManNickGのようなすべての動的条件が公開されています。たとえば、次のようになります。

void foo(boost::optional<T> const t&) {
    if (not t) { return; }

    t->bar();
}

であっても、間接参照はスローされるT::bar可能性があります(何もない場合)。もちろん、これは私たちがすでにこれを除外したという事実を無視しています(ここ)。noexceptoptional<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.
于 2013-02-01T18:38:30.233 に答える