首頁  >  文章  >  後端開發  >  以下是一些標題選項,每個標題都強調文章的不同面向: 選項 1:重點關注概念和 C 11 功能: * C 11 中的 ScopeGuard:簡單的錯誤處理,但有哪些注意事項

以下是一些標題選項,每個標題都強調文章的不同面向: 選項 1:重點關注概念和 C 11 功能: * C 11 中的 ScopeGuard:簡單的錯誤處理,但有哪些注意事項

Patricia Arquette
Patricia Arquette原創
2024-10-28 04:51:02648瀏覽

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,從而簡化錯誤和資源處理。以下是一個簡單的解釋和實現:

概念:

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>

在此範例中,Scope確保即使在函數範圍內引發異常,也會執行清理操作(從向量中彈出元素)。

簡單性和局限性:

ScopeGuard 習慣用法的這種實現相對簡單和簡潔,使其易於使用和理解。然而,原問題的作者也對潛在的缺陷或缺失的專業提出了擔憂。讓我們解決這些問題:

  • 完美轉發: 此實作並未充分利用 C 11 完美轉發技術。這在 makeScopeGuard 函數中很明顯,該函數使用左值引用而不是 lambda 參數的通用參考。使用通用引用將提供更大的靈活性並支援右值 lambda。
  • 如果取得拋出例外則回滾: 原始實作不處理「取得」lambda 拋出例外的情況。如果取得 lambda 失敗,則永遠不會呼叫回滾 lambda,從而使程式碼處於不一致的狀態。

為了解決這些問題,以下是 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中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn