泛型查找列表类





3.00/5 (1投票)
2000年10月13日

52094

470
一种简单的方法来保持 COM 实例等项目“温暖”并可重用。
引言
我最近需要维护一个“热”对象列表。 在我的例子中,这些是 ADO RecordsetPtr
和 CommandPtr
对象。 我正在处理的代码有大量例程,这些例程创建 RecordsetPtr
,执行 SQL 命令,查看结果,然后删除 RecordsetPtr
。 这些例程被一遍又一遍地调用,但没有简单的模式。
在查看性能跟踪时,我发现大量时间花费在创建 COM 对象实例然后销毁它们上。 我很快决定,我需要一种简单的方法来保持这些 COM 实例“热”并可供重用,并且这种机制应该尽可能少地更改现有代码。
显然,我需要的是一个预查列表。 当我没有找到完全符合要求的东西时,我感到惊讶,并决定构建一个相对简单的通用预查列表处理程序。
结果由两个模板类组成:lookaside
,它管理热对象集,以及 simpleIniter
,用于执行对象特定的初始化和销毁函数(请记住,我的目标是尽量减少代码中的其他更改,所以我决定不强制将每个包含的对象放入包装类中)。
lookaside
实例在其声明中接受两个模板参数:要存储的对象的类型,以及“initer”类,用于执行类型特定的初始化和销毁操作(见下文)。 构造函数还接受两个参数:预加载到预查列表中的对象数量,以及可以容纳在其中的最大对象数量。
lookaside
有两个主要方法,Get
和 Release
,以及少量支持方法。 总而言之,这些是
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
函数返回的任何对象都可以使用,无论它是刚创建的还是不是。
我已在下面包含了 lookaside
和 simpleIniter
类的源代码,它们也可以在上面列出的下载点找到。
// 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_