私は、いくつかの異なるテキスト配列を反復処理できるという問題を解決しようとしていました。それらはすべて、大規模なメモリ常駐データベース内に格納されていますstruct
。
以下は、MFCテストアプリケーションでVisual Studio 2017 Community Editionを使用して作成されました。この投稿は、私が遭遇したいくつかのヘルプの1つであるため、例として含めています。
struct
含むメモリ常駐のデータは次のようなものが見えました。簡潔にするために、ほとんどの要素を削除し、使用したプリプロセッサ定義も含めていません(使用中のSDKはCおよびC ++向けであり、古いものです)。
私が興味を持っていたのはWCHAR
、ニーモニック用のテキスト文字列を含むさまざまな2次元配列のイテレータを用意することです。
typedef struct tagUNINTRAM {
// stuff deleted ...
WCHAR ParaTransMnemo[MAX_TRANSM_NO][PARA_TRANSMNEMO_LEN]; /* prog #20 */
WCHAR ParaLeadThru[MAX_LEAD_NO][PARA_LEADTHRU_LEN]; /* prog #21 */
WCHAR ParaReportName[MAX_REPO_NO][PARA_REPORTNAME_LEN]; /* prog #22 */
WCHAR ParaSpeMnemo[MAX_SPEM_NO][PARA_SPEMNEMO_LEN]; /* prog #23 */
WCHAR ParaPCIF[MAX_PCIF_SIZE]; /* prog #39 */
WCHAR ParaAdjMnemo[MAX_ADJM_NO][PARA_ADJMNEMO_LEN]; /* prog #46 */
WCHAR ParaPrtModi[MAX_PRTMODI_NO][PARA_PRTMODI_LEN]; /* prog #47 */
WCHAR ParaMajorDEPT[MAX_MDEPT_NO][PARA_MAJORDEPT_LEN]; /* prog #48 */
// ... stuff deleted
} UNINIRAM;
現在のアプローチでは、テンプレートを使用して各配列のプロキシクラスを定義し、配列を表すプロキシオブジェクトを使用して特定の配列を反復処理するために使用できる単一の反復子クラスを使用します。
メモリ常駐データのコピーは、メモリ常駐データのディスクへの読み書きを処理するオブジェクトに格納されます。このクラスにCFilePara
は、テンプレート化されたプロキシクラス(MnemonicIteratorDimSize
およびその派生元のサブクラスMnemonicIteratorDimSizeBase
)と反復子クラスが含まれていMnemonicIterator
ます。
作成されたプロキシオブジェクトは、すべてのプロキシクラスの派生元である基本クラスによって記述されたインターフェイスを介して必要な情報にアクセスするイテレータオブジェクトにアタッチされます。その結果、複数の異なるプロキシクラスで使用できる単一のタイプのイテレータクラスができます。これは、異なるプロキシクラスがすべて同じインターフェイス、つまりプロキシベースクラスのインターフェイスを公開しているためです。
最初に、そのタイプのニーモニック用の特定のプロキシオブジェクトを生成するためにクラスファクトリに提供される識別子のセットを作成しました。これらの識別子は、ユーザーが表示したり、場合によっては変更したりすることに関心のある特定のプロビジョニングデータを識別するために、ユーザーインターフェイスの一部として使用されます。
const static DWORD_PTR dwId_TransactionMnemonic = 1;
const static DWORD_PTR dwId_ReportMnemonic = 2;
const static DWORD_PTR dwId_SpecialMnemonic = 3;
const static DWORD_PTR dwId_LeadThroughMnemonic = 4;
プロキシクラス
テンプレート化されたプロキシクラスとその基本クラスは次のとおりです。いくつかの異なる種類のwchar_t
テキスト文字列配列に対応する必要がありました。2次元配列は、ニーモニックの種類(目的)に応じて異なる数のニーモニックを持ち、異なるタイプのニーモニックは、最大長が異なり、5つのテキスト文字と20のテキスト文字の間で異なりました。派生プロキシクラスのテンプレートは、各ニーモニックで最大文字数を必要とするテンプレートに自然に適合しました。プロキシオブジェクトが作成されSetRange()
たら、メソッドを使用して、実際のニーモニック配列とその範囲を指定します。
// proxy object which represents a particular subsection of the
// memory resident database each of which is an array of wchar_t
// text arrays though the number of array elements may vary.
class MnemonicIteratorDimSizeBase
{
DWORD_PTR m_Type;
public:
MnemonicIteratorDimSizeBase(DWORD_PTR x) { }
virtual ~MnemonicIteratorDimSizeBase() { }
virtual wchar_t *begin() = 0;
virtual wchar_t *end() = 0;
virtual wchar_t *get(int i) = 0;
virtual int ItemSize() = 0;
virtual int ItemCount() = 0;
virtual DWORD_PTR ItemType() { return m_Type; }
};
template <size_t sDimSize>
class MnemonicIteratorDimSize : public MnemonicIteratorDimSizeBase
{
wchar_t (*m_begin)[sDimSize];
wchar_t (*m_end)[sDimSize];
public:
MnemonicIteratorDimSize(DWORD_PTR x) : MnemonicIteratorDimSizeBase(x), m_begin(0), m_end(0) { }
virtual ~MnemonicIteratorDimSize() { }
virtual wchar_t *begin() { return m_begin[0]; }
virtual wchar_t *end() { return m_end[0]; }
virtual wchar_t *get(int i) { return m_begin[i]; }
virtual int ItemSize() { return sDimSize; }
virtual int ItemCount() { return m_end - m_begin; }
void SetRange(wchar_t (*begin)[sDimSize], wchar_t (*end)[sDimSize]) {
m_begin = begin; m_end = end;
}
};
イテレータークラス
反復子クラス自体は次のとおりです。このクラスは、現時点で必要なすべての基本的な前方反復子機能を提供します。しかし、私はそれから何かが必要になったときに、これが変更または拡張されることを期待しています。
class MnemonicIterator
{
private:
MnemonicIteratorDimSizeBase *m_p; // we do not own this pointer. we just use it to access current item.
int m_index; // zero based index of item.
wchar_t *m_item; // value to be returned.
public:
MnemonicIterator(MnemonicIteratorDimSizeBase *p) : m_p(p) { }
~MnemonicIterator() { }
// a ranged for needs begin() and end() to determine the range.
// the range is up to but not including what end() returns.
MnemonicIterator & begin() { m_item = m_p->get(m_index = 0); return *this; } // begining of range of values for ranged for. first item
MnemonicIterator & end() { m_item = m_p->get(m_index = m_p->ItemCount()); return *this; } // end of range of values for ranged for. item after last item.
MnemonicIterator & operator ++ () { m_item = m_p->get(++m_index); return *this; } // prefix increment, ++p
MnemonicIterator & operator ++ (int i) { m_item = m_p->get(m_index++); return *this; } // postfix increment, p++
bool operator != (MnemonicIterator &p) { return **this != *p; } // minimum logical operator is not equal to
wchar_t * operator *() const { return m_item; } // dereference iterator to get what is pointed to
};
プロキシオブジェクトファクトリは、ニーモニック識別子に基づいて、作成するオブジェクトを決定します。プロキシオブジェクトが作成され、返されるポインターが標準の基本クラス型であるので、異なるニーモニックセクションのどれがアクセスされているかに関係なく、インターフェイスは統一されています。このSetRange()
メソッドは、プロキシが表す特定の配列要素と配列要素の範囲をプロキシオブジェクトに指定するために使用されます。
CFilePara::MnemonicIteratorDimSizeBase * CFilePara::MakeIterator(DWORD_PTR x)
{
CFilePara::MnemonicIteratorDimSizeBase *mi = nullptr;
switch (x) {
case dwId_TransactionMnemonic:
{
CFilePara::MnemonicIteratorDimSize<PARA_TRANSMNEMO_LEN> *mk = new CFilePara::MnemonicIteratorDimSize<PARA_TRANSMNEMO_LEN>(x);
mk->SetRange(&m_Para.ParaTransMnemo[0], &m_Para.ParaTransMnemo[MAX_TRANSM_NO]);
mi = mk;
}
break;
case dwId_ReportMnemonic:
{
CFilePara::MnemonicIteratorDimSize<PARA_REPORTNAME_LEN> *mk = new CFilePara::MnemonicIteratorDimSize<PARA_REPORTNAME_LEN>(x);
mk->SetRange(&m_Para.ParaReportName[0], &m_Para.ParaReportName[MAX_REPO_NO]);
mi = mk;
}
break;
case dwId_SpecialMnemonic:
{
CFilePara::MnemonicIteratorDimSize<PARA_SPEMNEMO_LEN> *mk = new CFilePara::MnemonicIteratorDimSize<PARA_SPEMNEMO_LEN>(x);
mk->SetRange(&m_Para.ParaSpeMnemo[0], &m_Para.ParaSpeMnemo[MAX_SPEM_NO]);
mi = mk;
}
break;
case dwId_LeadThroughMnemonic:
{
CFilePara::MnemonicIteratorDimSize<PARA_LEADTHRU_LEN> *mk = new CFilePara::MnemonicIteratorDimSize<PARA_LEADTHRU_LEN>(x);
mk->SetRange(&m_Para.ParaLeadThru[0], &m_Para.ParaLeadThru[MAX_LEAD_NO]);
mi = mk;
}
break;
}
return mi;
}
プロキシクラスとイテレータの使用
次のループに示すように、プロキシクラスとそのイテレータを使用してCListCtrl
、ニーモニックのリストをオブジェクトに入力します。私が使用しstd::unique_ptr
ているのは、プロキシクラスが不要になり、std::unique_ptr
スコープが外れたときに、メモリがクリーンアップされるようにするためです。
このソースコードが行うことはstruct
、指定されたニーモニック識別子に対応する内に配列のプロキシオブジェクトを作成することです。次に、そのオブジェクトのイテレータを作成し、ranged for
を使用してCListCtrl
コントロールに入力してからクリーンアップします。これらはすべて生のwchar_t
テキスト文字列であり、正確に配列要素の数になる可能性があるため、テキストがゼロで終了するように文字列を一時バッファにコピーします。
std::unique_ptr<CFilePara::MnemonicIteratorDimSizeBase> pObj(pFile->MakeIterator(m_IteratorType));
CFilePara::MnemonicIterator pIter(pObj.get()); // provide the raw pointer to the iterator who doesn't own it.
int i = 0; // CListCtrl index for zero based position to insert mnemonic.
for (auto x : pIter)
{
WCHAR szText[32] = { 0 }; // Temporary buffer.
wcsncpy_s(szText, 32, x, pObj->ItemSize());
m_mnemonicList.InsertItem(i, szText); i++;
}