65.9K
CodeProject 正在变化。 阅读更多。
Home

泛型查找列表类

starIconstarIconstarIconemptyStarIconemptyStarIcon

3.00/5 (1投票)

2000年10月13日

viewsIcon

52094

downloadIcon

470

一种简单的方法来保持 COM 实例等项目“温暖”并可重用。

  • 下载源代码文件 - 2 Kb
  • 引言

    我最近需要维护一个“热”对象列表。 在我的例子中,这些是 ADO RecordsetPtrCommandPtr 对象。 我正在处理的代码有大量例程,这些例程创建 RecordsetPtr,执行 SQL 命令,查看结果,然后删除 RecordsetPtr。 这些例程被一遍又一遍地调用,但没有简单的模式。

    在查看性能跟踪时,我发现大量时间花费在创建 COM 对象实例然后销毁它们上。 我很快决定,我需要一种简单的方法来保持这些 COM 实例“热”并可供重用,并且这种机制应该尽可能少地更改现有代码。

    显然,我需要的是一个预查列表。 当我没有找到完全符合要求的东西时,我感到惊讶,并决定构建一个相对简单的通用预查列表处理程序。

    结果由两个模板类组成:lookaside,它管理热对象集,以及 simpleIniter,用于执行对象特定的初始化和销毁函数(请记住,我的目标是尽量减少代码中的其他更改,所以我决定不强制将每个包含的对象放入包装类中)。

    lookaside 实例在其声明中接受两个模板参数:要存储的对象的类型,以及“initer”类,用于执行类型特定的初始化和销毁操作(见下文)。 构造函数还接受两个参数:预加载到预查列表中的对象数量,以及可以容纳在其中的最大对象数量。

    lookaside 有两个主要方法,GetRelease,以及少量支持方法。 总而言之,这些是

    • Get 返回指向热对象的指针,如果需要,它将创建一个。
    • Release 将对象返回到预查列表,并可能删除该对象。
    • Drain 删除当前保存在预查列表中的所有对象。
    • GetCurSize 返回当前保存在预查列表中的对象数量。
    • GetMaxSize 返回此预查列表可以保存的最大对象数量。

    基本代码还包括一个默认的“initer”类 simpleIniter,它为其四个方法执行有效的空操作。 这些是

    • init 在创建对象的新操作之后立即调用
    • activate 在将对象返回给使用者之前立即调用(通过 lookaside::Get
    • deactivate 在通过 lookaside::Release 将对象返回到预查列表之后立即调用
    • deinit 在销毁对象的删除操作之前立即调用。

    通常,所有这些例程都将有效地为空,并且 simpleIniter 涵盖了这些情况。 但是,作为一个例子,说明何时这些方法可能有用,请考虑我构建这个类的最初原因:维护 ADO 对象的预查列表。 在这种情况下,我构建了以下名为 ADOIniter 的变体

    template<class T>
    class ADOIniter
    {
    public:
                        ADOIniter ()        {};
    
        bool            init (T *p);
        bool            activate (T *p)     {return true;};
        bool            deactivate (T *p)   {return true;};
        void            deinit (T *p)       {return; };
    };
    

    此类与 simpleIniter 的不同之处在于它具有一个活动的 init 方法,用于创建适当的实例,例如

    bool ADOIniter<_CommandPtr>::init(_CommandPtr *p)
    {
        return SUCCEEDED (p -> CreateInstance (__uuidof (Command)));
    };
    
    bool ADOIniter<_RecordsetPtr>::init(_RecordsetPtr *p)
    {
        return SUCCEEDED (p -> CreateInstance (__uuidof (Recordset)));
    };
    

    这些方法确保从 Get 函数返回的任何对象都可以使用,无论它是刚创建的还是不是。

    我已在下面包含了 lookasidesimpleIniter 类的源代码,它们也可以在上面列出的下载点找到。

    // Copyright (c): 2000, Software Exploration, Inc.
    
    //
    
    // This file is provided "as is" with no expressed or implied warranty.
    
    // The author accepts no liability for any damage/loss of business that
    
    // this product may cause.
    
    //
    
    // This code may be used in compiled form in any way you desire. This
    
    // file may be redistributed unmodified by any means PROVIDING it is
    
    // not sold for profit without the author's written consent, and
    
    // providing that this notice, the contact information, and all copyright
    
    // notices remains intact. If the source code in this file is used in
    
    // any  commercial application then a statement along the lines of
    
    // "Portions copyright (c): 2000, Software Exploration, Inc" must be
    
    // included in the startup banner, "About" box or printed documentation.
    
    //
    
    //
    
    // Contact Information:
    
    //      Author:             James E Johnson
    
    //      email:              Jim.Johnson@software-exploration.com
    
    //      website:            http://www.software-exploration.com
    
    //      source location:    ftp://downloads.software-exploration.com/lookaside.zip
    
    //
    
    
    // Description:
    
    //
    
    //
    
    //
    
    
    #ifndef _LOOKASIDE_H_
    #define _LOOKASIDE_H_
    
    #include <list>
    
    
    // simpleIniter: Simple initialization/deactivation worker class
    
    //
    
    //  This class handles the initialization/activation/deactivation/teardown of
    
    //  simple objects that need no other setup or teardown aside from new & delete.
    
    //
    
    //  More complex objects should implement the equivalent class interface and
    
    //  use it in their declaration of a lookaside object.
    
    //
    
    // Interface:
    
    //
    
    //  This class has four methods that are used by the lookaside class:
    
    //
    
    //      init:       this method is called post-new, but before any decision has
    
    //                  been made to return the object to a consumer.
    
    //
    
    //      activate:   this method is called just before returning the object in a
    
    //                  Get call.
    
    //
    
    //      deactivate: This method is called at the start of a Release call.
    
    //
    
    //      deinit:     This method is called just before the object is deleted.
    
    //
    
    
    template<class T>
    class simpleIniter
    {
    public:
                        simpleIniter ()     {};
    
        bool            init (T *p)         {return true;};
        bool            activate (T *p)     {return true;};
        bool            deactivate (T *p)   {return true;};
        void            deinit (T *p)       {return; };
    };
    
    // lookaside: Generic Lookaside list handler
    
    //
    
    //  This class implements a simple, generic lookaside list manager.  It attempts
    
    //  to keep a set of 'warm' objects ready for use, with limits on how many to
    
    //  maintain ready for use.
    
    //
    
    // Interface:
    
    //
    
    //  This class has the following interface:
    
    //
    
    //      (construction): lookaside foo (min, max)
    
    //      The constructor can accept a maximum number of 'warm' objects to keep
    
    //      around, and the minimum number of 'warm' objects to activate in the
    
    //      constructor.
    
    //
    
    //      (destruction):  ~lookaside
    
    //      No parameters.  Destroys any 'warm' objects currently held on the
    
    //      lookaside list.
    
    //
    
    //      Retrieval interfaces:
    
    //
    
    //      Get:            This returns a pointer to an object that is available
    
    //                      for use, or a null pointer, if an object could not be
    
    //                      made available.
    
    //
    
    //      Release (ptr, DontReuse):
    
    //                      Return control of an object to the lookaside list.  If
    
    //                      the DontReuse flag is true, the object is deleted rather
    
    //                      than made available for a later consumer.
    
    //
    
    //      Drain:          Delete all objects currently held 'warm' in the lookaside
    
    //                      list.
    
    //
    
    //      Informational interfaces:
    
    //
    
    //      GetCurSize:     Returns the number of items currently held 'warm' in the
    
    //                      lookaside list.
    
    //
    
    //      GetMaxSize:     Returns the maximum number of items that may be held 'warm'
    
    //                      in the list.
    
    //
    
    //
    
    template<class T, class A = simpleIniter<T> >
    class lookaside
    {
    public:
                        lookaside (int nMin = 0, int nMax = 1)
                        {
                            m_nMax = nMax;
                            if (nMin > nMax) nMin = nMax;
    
                            FillToMin (nMin);
                        };
    
        virtual         ~lookaside ()
                        {
                            Drain ();
                        }
    
        T               *Get (void)
                        {
                            T   *pRes;
                            if (!m_lstFreeElems.empty ())
                            {
                                pRes = m_lstFreeElems.front ();
                                m_lstFreeElems.pop_front ();
                            }
                            else
                                pRes = NewElem ();
    
                            if (!m_Initer.activate (pRes))
                            {
                                Release (pRes, true);
                                pRes = NULL;
                            }
    
                            return pRes;
                        };
    
        void            Release (T *p, bool fDontReuse = false)
                        {
                            fDontReuse |= !m_Initer.deactivate (p);
                            if (fDontReuse)     DeleteEntry (p);
                            else                m_lstFreeElems.push_back (p);
    
                            while (m_lstFreeElems.size () > m_nMax)
                            {
                                T *p = m_lstFreeElems.front ();
                                m_lstFreeElems.pop_front ();
                                DeleteEntry (p);
                            }
                        };
    
        void            Drain (void)
                        {
                            while (!m_lstFreeElems.empty ())
                            {
                                T *p = m_lstFreeElems.front ();
                                m_lstFreeElems.pop_front ();
                                DeleteEntry (p);
                            }
                        };
    
        int             GetCurSize () const     {return m_lstFreeElems.size (); };
        int             GetMaxSize () const     {return m_nMax; };
    
    private:
        int             m_nMax;                 // Maximum allowable size of the list
    
    
        std::list<T *>  m_lstFreeElems;         // Warm object list
    
        A               m_Initer;               // The contained initializer object
    
    
        // Allocate and initialize a new object.
    
        //
    
        T               *NewElem ()
                        {
                            T *p = new T;
                            m_Initer.init (p);
    
                            return p;
                        };
    
        // Fill the lookaside list to at least the level supplied by nMin.
    
        //
    
        void            FillToMin (int nMin)
                        {
                            while (m_lstFreeElems.size () < nMin)
                            {
                                T   *p = NewElem ();
                                m_lstFreeElems.push_back (p);
                            }
                        };
    
        // de-initialize and delete a warm object
    
        //
    
        void            DeleteEntry (T *p)
                        {
                            m_Initer.deinit (p);
                            delete p;
                        };
    };
    
    #endif // _LOOKASIDE_H_
    
    
    © . All rights reserved.