以下にいくつかのタイトルのオプションを示します。それぞれが記事の異なる側面を強調しています。 オプション 1: コンセプトと C 11 機能に焦点を当てる: * C 11 の ScopeGuard: 単純なエラー処理ですが、注意点があります

Patricia Arquette
リリース: 2024-10-28 04:51:02
オリジナル
647 人が閲覧しました

Here are a few title options, each emphasizing a different aspect of the article:

Option 1: Focusing on the concept and C  11 feature:

* ScopeGuard in C  11: Simple Error Handling, But Which Caveats? 

Option 2: Highlighting the simplicity and limitatio

最も単純できちんとした C 11 ScopeGuard

C 11 には、エラーとリソースの処理を簡素化する ScopeGuard を実装するための単純なイディオムがあります。以下に簡単な説明と実装を示します:

概念:

ScopeGuard は、次の場合に自動的に実行されるコード ブロックを定義する方法を提供する C クラスです。ガードが作成されたスコープが終了します。これにより、クリーンアップとエラー処理が簡単になり、例外的な状況でもリソースが解放されたり、アクションが実行されたりすることが保証されます。

実装:

<code class="cpp">namespace RAII
{
    template< typename Lambda >
    class ScopeGuard
    {
        mutable bool committed;
        Lambda rollbackLambda; 
        public:

            ScopeGuard( const Lambda&amp; _l) : committed(false) , rollbackLambda(_l) {}

            template< typename AdquireLambda >
            ScopeGuard( const AdquireLambda&amp; _al , const Lambda&amp; _l) : committed(false) , rollbackLambda(_l)
            {
                _al();
            }

            ~ScopeGuard()
            {
                if (!committed)
                    rollbackLambda();
            }
            inline void commit() const { committed = true; }
    };

    template< typename aLambda , typename rLambda>
    const ScopeGuard< rLambda >&amp; makeScopeGuard( const aLambda&amp; _a , const rLambda&amp; _r)
    {
        return ScopeGuard< rLambda >( _a , _r );
    }

    template<typename rLambda>
    const ScopeGuard< rLambda >&amp; makeScopeGuard(const rLambda&amp; _r)
    {
        return ScopeGuard< rLambda >(_r );
    }
}</code>
ログイン後にコピー

使用法:

<code class="cpp">void SomeFuncThatShouldBehaveAtomicallyInCaseOfExceptions() 
{
   std::vector<int> myVec;
   std::vector<int> someOtherVec;

   myVec.push_back(5);
   //first constructor, adquire happens elsewhere
   const auto&amp; a = RAII::makeScopeGuard( [&amp;]() { myVec.pop_back(); } );  

   //sintactically neater, since everything happens in a single line
   const auto&amp; b = RAII::makeScopeGuard( [&amp;]() { someOtherVec.push_back(42); }
                     , [&amp;]() { someOtherVec.pop_back(); } ); 

   b.commit();
   a.commit();
}</code>
ログイン後にコピー

この例では、ScopeGuard イディオムを使用して、関数のスコープ内で例外がスローされた場合でもクリーンアップ アクション (ベクトルから要素をポップする) が確実に実行されるようにします。

単純さと制限:

ScopeGuard イディオムのこの実装は比較的単純かつ簡潔であるため、使いやすく、理解しやすくなっています。ただし、元の質問の作成者は、潜在的な欠点や専門分野の欠落についての懸念も提起しました。これらに対処しましょう:

  • 完全転送: この実装では、C 11 完全転送技術が完全には活用されていません。これは、ラムダ パラメーターのユニバーサル参照の代わりに左辺値参照を使用する makeScopeGuard 関数で明らかです。ユニバーサル参照を使用すると、柔軟性が向上し、右辺値ラムダのサポートが可能になります。
  • Rollback If Acquire Throws: 元の実装では、「acquire」ラムダが例外をスローする場合は処理されません。ラムダの取得が失敗した場合、ロールバック ラムダは呼び出されず、コードは一貫性のない状態のままになります。

これらの懸念に対処するために、ScopeGuard の実装と使用法の更新バージョンを次に示します。

<code class="cpp">namespace RAII
{
    template< typename Lambda >
    class ScopeGuard
    {
        bool committed;
        Lambda rollbackLambda; 
        public:

            ScopeGuard( const Lambda&amp; _l) : committed(false) , rollbackLambda(_l) {}

            ScopeGuard( const ScopeGuard&amp; _sc) : committed(false) , rollbackLambda(_sc.rollbackLambda) 
            {
                if (_sc.committed)
                   committed = true;
                else
                   _sc.commit();
            }

            ScopeGuard( ScopeGuard&amp;&amp; _sc) : committed(false) , rollbackLambda(_sc.rollbackLambda)
            {
                if (_sc.committed)
                   committed = true;
                else
                   _sc.commit();
            }

            //WARNING: only safe if adquire lambda does not throw, otherwise release lambda is never invoked, because the scope guard never finished initialistion..
            template< typename AdquireLambda >
            ScopeGuard( const AdquireLambda&amp; _al , const Lambda&amp; _l) : committed(false) , rollbackLambda(_l)
            {
               std::forward<AdquireLambda>(_al)();
            }

            //WARNING: only safe if adquire lambda does not throw, otherwise release lambda is never invoked, because the scope guard never finished initialistion..
            template< typename AdquireLambda, typename L >
            ScopeGuard( AdquireLambda&amp;&amp; _al , L&amp;&amp; _l) : committed(false) , rollbackLambda(std::forward<L>(_l))
            {
                std::forward<AdquireLambda>(_al)(); // just in case the functor has &amp;&amp;-qualified operator()
            }


            ~ScopeGuard()
            {
                if (!committed)
                    rollbackLambda();
            }
            inline void commit() { committed = true; }
    };


    //WARNING: only safe if adquire lambda does not throw, otherwise release lambda is never invoked, because the scope guard never finished initialistion..
    template< typename aLambda , typename rLambda>
    ScopeGuard< rLambda > // return by value is the preferred C++11 way.
    makeScopeGuardThatDoesNOTRollbackIfAdquireThrows( aLambda&amp;&amp; _a , rLambda&amp;&amp; _r) // again perfect forwarding
    {
        return ScopeGuard< rLambda >( std::forward<aLambda>(_a) , std::forward<rLambda>(_r )); // *** no longer UB, because we're returning by value
    }

    template< typename aLambda , typename rLambda>
    ScopeGuard< rLambda > // return by value is the preferred C++11 way.
    makeScopeGuardThatDoesRollbackIfAdquireThrows( aLambda&amp;&amp; _a , rLambda&amp;&amp; _r) // again perfect forwarding
    {
        auto scope = ScopeGuard< rLambda >(std::forward<rLambda>(_r )); // *** no longer UB, because we're returning by value
        _a();
        return scope;
    }

    template<typename rLambda>
    ScopeGuard< rLambda > makeScopeGuard(rLambda&amp;&amp; _r)
    {
        return ScopeGuard< rLambda >( std::forward<rLambda>(_r ));
    }

    namespace basic_usage
    {
        struct Test
        {

            std::vector<int> myVec;
            std::vector<int> someOtherVec;
            bool shouldThrow;
            void run()
            {
                shouldThrow = true;
                try
                {
                    SomeFuncThatShouldBehaveAtomicallyInCaseOfExceptionsUsingScopeGuardsThatDoesNOTRollbackIfAdquireThrows();
                } catch (...)
                {
                    AssertMsg( myVec.size() == 0 &amp;&amp; someOtherVec.size() == 0 , "rollback did not work");
                }
                shouldThrow = false;
                SomeFuncThatShouldBehaveAtomicallyInCaseOfExceptionsUsingScopeGuardsThatDoesNOTRollbackIfAdquireThrows();
                AssertMsg( myVec.size() == 1 &amp;&amp; someOtherVec.size() == 1 , "unexpected end state");
                shouldThrow = true;
                myVec.clear(); someOtherVec.clear();  
                try
                {
                    SomeFuncThatShouldBehaveAtomicallyInCaseOfExceptionsUsingScopeGuardsThatDoesRollbackIfAdquireThrows();
                } catch (...)
                {
                    AssertMsg( myVec.size() == 0 &amp;&amp; someOtherVec.size() == 0 , "rollback did not work");
                }
            }

            void SomeFuncThatShouldBehaveAtomicallyInCaseOfExceptionsUsingScopeGuardsThatDoesNOTRollbackIfAdquireThrows() //throw()
            {

                myVec.push_back(42);</code>
ログイン後にコピー

以上が以下にいくつかのタイトルのオプションを示します。それぞれが記事の異なる側面を強調しています。 オプション 1: コンセプトと C 11 機能に焦点を当てる: * C 11 の ScopeGuard: 単純なエラー処理ですが、注意点がありますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!