2

強力な例外安全保証は、例外が発生した場合、操作によってプログラムの状態が変更されないことを示しています。例外セーフなコピー代入を実装する洗練された方法は、コピー アンド スワップ イディオムです。

私の質問は次のとおりです。

  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

4 に答える 4

3

常に基本的な例外保証を目指す必要があります。例外が発生した場合、すべてのリソースが正しく解放され、オブジェクトが有効な状態 (未定義の可能性がありますが有効) であることを確認してください。

強力な例外保証 (つまり「トランザクション」) は、それが理にかなっている場合に実装する必要があります。常にトランザクションの動作が必要なわけではありません。

トランザクション操作を実行するのが簡単な場合 (例: コピー & スワップを介して)、それを実行します。ただし、代入演算子などの基本的なものであっても、そうでない場合や、パフォーマンスに大きな影響を与える場合があります。コピー割り当てで常に強力な保証を提供できるとは限らなかったboost::variantのようなものを実装したことを覚えています。

遭遇する大きな困難の 1 つは、移動セマンティクスに関するものです。そうしないと、移動したオブジェクトが失われるため、移動するときにトランザクションが必要です。ただし、常に強力な保証を提供できるとは限りません。考えてstd::pair<movable_nothrow, copyable>みてください (コメントを参照してください)。これは、あなたがnoexcept名人になり、不快な量のメタプログラミングを使用しなければならないところです。C++ は、例外の安全性のために正確にマスターすることは困難です。

于 2012-03-28T14:35:07.947 に答える
2

エンジニアリングのすべての問題と同様に、バランスが重要です。

確かに、const-ness/不変性と強力な保証は、コードの信頼性を高めます (特にテストを伴う場合)。また、バグの可能性のある説明のスペースを削減するのにも役立ちます。

ただし、パフォーマンスに影響を与える可能性があります。

すべてのパフォーマンスの問題と同様に、プロファイリングを行い、ホット スポットを取り除きます。Copy And Swap がトランザクション セマンティクスを実現する唯一の方法ではないことは確かです (これが最も簡単な方法です)。

于 2012-03-28T14:36:52.610 に答える
1

それは、アプリケーションが実行される環境によって異なります。自分のマシン (スペクトルの一端) で実行するだけの場合は、例外の安全性について厳しすぎる価値はないかもしれません。たとえば医療機器 (もう一方の端) 用のプログラムを作成している場合、例外が発生したときに意図しない副作用を残したくありません。その中間は、エラーに対する許容レベルと開発に利用できるリソース (時間、お金など) に依存します。

于 2012-03-28T14:34:34.530 に答える
0

はい、あなたが直面している問題は、このイディオムはスケーリングが非常に難しいということです。他の回答ではそれについて言及されていませんでしたが、 Alexandrescu によって発明されたscopeGuardsと呼ばれる別の非常に興味深いイディオムです。コードの経済性を高め、強力な例外安全保証に準拠する必要がある関数の可読性を大幅に改善します。

スコープ ガードの考え方は、ロールバック関数オブジェクトを各リソース取得にアタッチするだけのスタック インスタンスです。スコープ ガードが (例外によって) 破棄されると、ロールバックが呼び出されます。commit()スコープ終了時のロールバック呼び出しを回避するには、通常のフローで明示的に呼び出す必要があります。

C ++ 11機能を使用して安全なスコープガードを設計することに関連する、私からのこの最近の質問を確認してください。

于 2012-04-23T17:24:15.683 に答える