> 백엔드 개발 > C++ > 본문

다음은 기사의 다양한 측면을 강조하는 몇 가지 제목 옵션입니다. 옵션 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 완벽한 전달 기술을 완전히 활용하지 않습니다. 이는 람다 매개변수에 대한 범용 참조 대신 lvalue 참조를 사용하는 makeScopeGuard 함수에서 분명하게 나타납니다. 범용 참조를 사용하면 rvalue 람다에 대한 더 큰 유연성과 지원이 가능합니다.
  • Acquire Throws 경우 롤백: 원래 구현에서는 "acquire" 람다가 예외를 throw하는 경우를 처리하지 않습니다. 람다 획득이 실패하면 롤백 람다가 호출되지 않아 코드가 일관되지 않은 상태가 됩니다.

이러한 문제를 해결하기 위해 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!