zoukankan      html  css  js  c++  java
  • 重构ATL中的CAutoVectorPtr, CAutoPtr和CAutoStackPtr

    看到ATL中有3个类的代码比较比较重复,在atlbase.h中,分别是CAutoVectorPtr, CAutoPtr和CAutoStackPtr,他们的功能其实很类似STL中的autoptr, 但是这里因为针对不同的分配对象而用了3个不同的类,其中CAutoVectorPtr是针对数组类型的,CAutoPtr是针对普通的非数组类型,而CAutoStackPtr针对的是_malloca分配的类型,因为最后释放方式的不同,它这里用了3份代码来实现。

    CAutoVectorPtr:
    template< typename T >
    class CAutoVectorPtr
    {
    public:
        CAutoVectorPtr() throw() :
            m_p( NULL )
        {
        }
        CAutoVectorPtr( CAutoVectorPtr< T >& p ) throw()
        {
            m_p = p.Detach();  // Transfer ownership
        }
        explicit CAutoVectorPtr( T* p ) throw() :
            m_p( p )
        {
        }
        ~CAutoVectorPtr() throw()
        {
            Free();
        }

        operator T*() const throw()
        {
            return( m_p );
        }

        CAutoVectorPtr< T >& operator=( CAutoVectorPtr< T >& p ) throw()
        {
            if(*this==p)
            {
                if(m_p == NULL)
                {
                    // This branch means both two pointers are NULL, do nothing.
                }
                else if(this!=&p)
                {
                    // If this assert fires, it means you attempted to assign one CAutoVectorPtr to another when they both contained 
                    
    // a pointer to the same underlying vector. This means a bug in your code, since your vector will get 
                    
    // double-deleted. 
                    ATLASSERT(FALSE);

                    // For safety, we are going to detach the other CAutoVectorPtr to avoid a double-free. Your code still
                    
    // has a bug, though.
                    p.Detach();
                }
                else
                {
                    // Alternatively, this branch means that you are assigning a CAutoVectorPtr to itself, which is
                    
    // pointless but permissible

                    
    // nothing to do
                }
            }
            else
            {
                Free();
                Attach( p.Detach() );  // Transfer ownership
            }
            return( *this );
        }

        // basic comparison operators
        bool operator!=(CAutoVectorPtr<T>& p) const
        {
            return !operator==(p);
        }

        bool operator==(CAutoVectorPtr<T>& p) const
        {
            return m_p==p.m_p;
        }

        // Allocate the vector
        bool Allocate( size_t nElements ) throw()
        {
            ATLASSUME( m_p == NULL );
            ATLTRY( m_p = new T[nElements] );
            if( m_p == NULL )
            {
                returnfalse );
            }

            returntrue );
        }
        // Attach to an existing pointer (takes ownership)
        void Attach( T* p ) throw()
        {
            ATLASSUME( m_p == NULL );
            m_p = p;
        }
        // Detach the pointer (releases ownership)
        T* Detach() throw()
        {
            T* p;

            p = m_p;
            m_p = NULL;

            return( p );
        }
        // Delete the vector pointed to, and set the pointer to NULL
        void Free() throw()
        {
            delete[] m_p;
            m_p = NULL;
        }

    public:
        T* m_p;
    };



    CAutoPtr:
    template< typename T >
    class CAutoPtr
    {
    public:
        CAutoPtr() throw() :
            m_p( NULL )
        {
        }
        template< typename TSrc >
        CAutoPtr( CAutoPtr< TSrc >& p ) throw()
        {
            m_p = p.Detach();  // Transfer ownership
        }
        CAutoPtr( CAutoPtr< T >& p ) throw()
        {
            m_p = p.Detach();  // Transfer ownership
        }
        explicit CAutoPtr( T* p ) throw() :
            m_p( p )
        {
        }
        ~CAutoPtr() throw()
        {
            Free();
        }

        // Templated version to allow pBase = pDerived
        template< typename TSrc >
        CAutoPtr< T >& operator=( CAutoPtr< TSrc >& p ) throw()
        {
            if(m_p==p.m_p)
            {
                // This means that two CAutoPtrs of two different types had the same m_p in them
                
    // which is never correct
                ATLASSERT(FALSE);
            }
            else
            {
                Free();
                Attach( p.Detach() );  // Transfer ownership
            }
            return( *this );
        }
        CAutoPtr< T >& operator=( CAutoPtr< T >& p ) throw()
        {
            if(*this==p)
            {
                if(this!=&p)
                {
                    // If this assert fires, it means you attempted to assign one CAutoPtr to another when they both contained 
                    
    // a pointer to the same underlying object. This means a bug in your code, since your object will get 
                    
    // double-deleted. 
    #ifdef ATL_AUTOPTR_ASSIGNMENT_ASSERT
                    ATLASSERT(FALSE);
    #endif

                    // For safety, we are going to detach the other CAutoPtr to avoid a double-free. Your code still
                    
    // has a bug, though.
                    p.Detach();
                }
                else
                {
                    // Alternatively, this branch means that you are assigning a CAutoPtr to itself, which is
                    
    // pointless but permissible

                    
    // nothing to do
                }
            }
            else
            {
                Free();
                Attach( p.Detach() );  // Transfer ownership
            }
            return( *this );
        }

        // basic comparison operators
        bool operator!=(CAutoPtr<T>& p) const
        {
            return !operator==(p);
        }

        bool operator==(CAutoPtr<T>& p) const
        {
            return m_p==p.m_p;
        }

        operator T*() const throw()
        {
            return( m_p );
        }
        T* operator->() const throw()
        {
            ATLASSUME( m_p != NULL );
            return( m_p );
        }

        // Attach to an existing pointer (takes ownership)
        void Attach( T* p ) throw()
        {
            ATLASSUME( m_p == NULL );
            m_p = p;
        }
        // Detach the pointer (releases ownership)
        T* Detach() throw()
        {
            T* p;

            p = m_p;
            m_p = NULL;

            return( p );
        }
        // Delete the object pointed to, and set the pointer to NULL
        void Free() throw()
        {
            delete m_p;
            m_p = NULL;
        }

    public:
        T* m_p;
    };

    CAutoStackPtr:
    /* Automatic cleanup for _malloca objects */
    template< typename T >
    class CAutoStackPtr
    {
    public:
        CAutoStackPtr() throw() :
            m_p( NULL )
        {
        }
        template< typename TSrc >
        CAutoStackPtr( CAutoStackPtr< TSrc >& p ) throw()
        {
            m_p = p.Detach();  // Transfer ownership
        }
        CAutoStackPtr( CAutoStackPtr< T >& p ) throw()
        {
            m_p = p.Detach();  // Transfer ownership
        }
        explicit CAutoStackPtr( T* p ) throw() :
            m_p( p )
        {
        }
        ~CAutoStackPtr() throw()
        {
            Free();
        }

        // Templated version to allow pBase = pDerived
        template< typename TSrc >
        CAutoStackPtr< T >& operator=( CAutoStackPtr< TSrc >& p ) throw()
        {
            if(m_p==p.m_p)
            {
                // This means that two CAutoPtrs of two different types had the same m_p in them
                
    // which is never correct
                ATLASSERT(FALSE);
            }
            else
            {
                Free();
                Attach( p.Detach() );  // Transfer ownership
            }
            return( *this );
        }
        CAutoStackPtr< T >& operator=( CAutoStackPtr< T >& p ) throw()
        {
            if(*this==p)
            {
                if(this!=&p)
                {
                    // If this assert fires, it means you attempted to assign one CAutoPtr to another when they both contained 
                    
    // a pointer to the same underlying object. This means a bug in your code, since your object will get 
                    
    // double-deleted. 
                    ATLASSERT(FALSE);

                    // For safety, we are going to detach the other CAutoPtr to avoid a double-free. Your code still
                    
    // has a bug, though.
                    p.Detach();
                }
                else
                {
                    // Alternatively, this branch means that you are assigning a CAutoPtr to itself, which is
                    
    // pointless but permissible

                    
    // nothing to do
                }
            }
            else
            {
                Free();
                Attach( p.Detach() );  // Transfer ownership
            }
            return( *this );
        }

        // basic comparison operators
        bool operator!=(CAutoStackPtr<T>& p) const
        {
            return !operator==(p);
        }

        bool operator==(CAutoStackPtr<T>& p) const
        {
            return m_p==p.m_p;
        }

        operator T*() const throw()
        {
            return( m_p );
        }
        T* operator->() const throw()
        {
            ATLASSUME( m_p != NULL );
            return( m_p );
        }

        // Attach to an existing pointer (takes ownership)
        void Attach( T* p ) throw()
        {
            ATLASSUME( m_p == NULL );
            m_p = p;
        }
        // Detach the pointer (releases ownership)
        T* Detach() throw()
        {
            T* p;

            p = m_p;
            m_p = NULL;

            return( p );
        }
        // Delete the object pointed to, and set the pointer to NULL
        void Free() throw()
        {
            /* Note: _freea only actually does anything if m_p was heap allocated
               If m_p was from the stack, it wouldn't be possible to actually free it here
               [wrong function] unless we got inlined. But really all we do if m_p is 
               stack-based is ignore it and let its alloca storage disappear at the end
               of the outer function.
            
    */
            _freea(m_p);
            m_p = NULL;
        }

    public:
        T* m_p;
    };

    可以看到上面代码明显非常重复,不知道ATL这样写是不是历史原因,我们下面尝试对它进行重构。

    可以看到其实他们只是最终释放(Free)的时候稍微有些差别,我们明显可以把写差别提取出来,作为一个释放的Policy。

    struct DeleteFunctor
    {
        template<typename T> static void Release(T* p) { delete p; }
    };

    struct DeleteArrayFunctor
    {
        template<typename T> static void Release(T* p) { delete []p; }
    };

    struct DeleteStackFunctor
    {
        template<typename T> static void Release(T* p) { _freea p; }
    };

    然后我们把上面的各种释放行为作为一个模板参数传进去就可以了,代码如下:
    template< typename T, typename ReleasePolicy>
    class CAutoReleasePtr
    {
    public:
        CAutoReleasePtr() throw() :
          m_p( NULL )
          {
          }
          template< typename TSrc >
          CAutoReleasePtr( CAutoReleasePtr< TSrc >& p ) throw()
          {
              m_p = p.Detach();  // Transfer ownership
          }
          CAutoReleasePtr( CAutoReleasePtr< T >& p ) throw()
          {
              m_p = p.Detach();  // Transfer ownership
          }
          explicit CAutoReleasePtr( T* p ) throw() :
          m_p( p )
          {
          }
          ~CAutoReleasePtr() throw()
          {
              Free();
          }

          // Templated version to allow pBase = pDerived
          template< typename TSrc >
          CAutoReleasePtr< T >& operator=( CAutoReleasePtr< TSrc >& p ) throw()
          {
              if(m_p==p.m_p)
              {
                  // This means that two CAutoPtrs of two different types had the same m_p in them
                  
    // which is never correct
                  ATLASSERT(FALSE);
              }
              else
              {
                  Free();
                  Attach( p.Detach() );  // Transfer ownership
              }
              return( *this );
          }
          CAutoReleasePtr< T >& operator=( CAutoReleasePtr< T >& p ) throw()
          {
              if(*this==p)
              {
                  if(this!=&p)
                  {
                      // If this assert fires, it means you attempted to assign one CAutoPtr to another when they both contained 
                      
    // a pointer to the same underlying object. This means a bug in your code, since your object will get 
                      
    // double-deleted. 
    #ifdef ATL_AUTOPTR_ASSIGNMENT_ASSERT
                      ATLASSERT(FALSE);
    #endif

                      // For safety, we are going to detach the other CAutoPtr to avoid a double-free. Your code still
                      
    // has a bug, though.
                      p.Detach();
                  }
                  else
                  {
                      // Alternatively, this branch means that you are assigning a CAutoPtr to itself, which is
                      
    // pointless but permissible

                      
    // nothing to do
                  }
              }
              else
              {
                  Free();
                  Attach( p.Detach() );  // Transfer ownership
              }
              return( *this );
          }

          // basic comparison operators
          bool operator!=(CAutoReleasePtr<T>& p) const
          {
              return !operator==(p);
          }

          bool operator==(CAutoReleasePtr<T>& p) const
          {
              return m_p==p.m_p;
          }

          operator T*() const throw()
          {
              return( m_p );
          }
          T* operator->() const throw()
          {
              ATLASSUME( m_p != NULL );
              return( m_p );
          }

          // Attach to an existing pointer (takes ownership)
          void Attach( T* p ) throw()
          {
              ATLASSUME( m_p == NULL );
              m_p = p;
          }
          // Detach the pointer (releases ownership)
          T* Detach() throw()
          {
              T* p;

              p = m_p;
              m_p = NULL;

              return( p );
          }
          // Delete the object pointed to, and set the pointer to NULL
          void Free() throw()
          {
              ReleasePolicy::Release(m_p);
              m_p = NULL;
          }

    public:
        T* m_p;
    };

    可以看到我们上面其实就改了一行代码,改了下最终的释放策略.

    好,现在我们可以这样用了:
    CAutoReleasePtr<T, DeleteFunctor> p1(new int);
    CAutoReleasePtr<T, DeleteArrayFunctor> p2(new int[10]);
    功能是可以了,但是是不是觉得上面这样用起来不方便,typedef一下就好了:
     typedef CAutoReleasePtr<T, DeleteFunctor> CSimplePtr<T>;
     typedef CAutoReleasePtr<T, DeleteArrayFunctor> CArrayPtr<T>;
     typedef CAutoReleasePtr<T, DeleteStackFunctor> CStackPtr<T>;
    但是我们很块发现上面的代码编译都过不了。

    既然typedef不行,那我们就通过继承来生成一个新类:
    template<typename T> class CSimplePtr: public CAutoReleasePtr<T, DeleteFunctor> {};
    template<typename T> class CArrayPtr: public CAutoReleasePtr<T, DeleteArrayFunctor> {};
    template<typename T> class CStackPtr: public CAutoReleasePtr<T, DeleteStackFunctor> {};
    我们很快又发现,用不起来,我们新类的构造函数需要重写才行。

    接下来我们考虑生成一个新类,然后在内部typedef:
     template<typename T>
     struct CSimplePtr
     {
         typedef CAutoReleasePtr<T, DeleteFunctor> type;
     };
     
     template<typename T>
     struct CArrayPtr
     {
         typedef CAutoReleasePtr<T, DeleteArrayFunctor> type;
     };
     
     template<typename T>
     struct CStackPtr
     {
         typedef CAutoReleasePtr<T, DeleteStackFunctor> type;
     };
    然后这样用:
    CSimplePtr<int>::type p(new int);
    CArrayPtr<int>::type p1(new int[20]);
    可是这样用和最初的用法似乎又没多少改进....

    再最后想到了用宏:
    #define CSimplePtr(T) CAutoReleasePtr<T, DeleteFunctor>
    #define CArrayPtr(T) CAutoReleasePtr<T, DeleteArrayFunctor>
    但是用的时候太呕心了:
    CSimplePtr(int) p(new int);
    CArrayPtr(int) p1(new int[20]);

    最后,实在没有什么办法了....
    不知道大家有没有什么好方法 ???
  • 相关阅读:
    Python绘图与可视化
    ArcGIS Python人门到精通目录基于ArcGIS10.2,100以上案例15章42个视频806分钟,51GIS网站上线
    arcpy 重分类
    pythonw.exe不能用
    Pyhton 单行、多行注释符号使用方法及规范
    NumPyArray
    python 日期
    solr多core的处理
    如何在Solr中实现多core查询
    solr之高级查询--联表 join查询
  • 原文地址:https://www.cnblogs.com/weiym/p/2700815.html
Copyright © 2011-2022 走看看