Saya sedang mencoba untuk memecahkan masalah untuk dapat mengulangi beberapa array teks yang berbeda yang semuanya disimpan dalam database memori yang besar struct
.
Berikut ini dikerjakan menggunakan Visual Studio 2017 Community Edition pada aplikasi tes MFC. Saya memasukkan ini sebagai contoh karena posting ini adalah salah satu dari beberapa yang saya temui yang memberikan bantuan namun masih kurang untuk kebutuhan saya.
Yang struct
berisi data penduduk memori tampak seperti berikut ini. Saya telah menghapus sebagian besar elemen demi singkatnya dan juga belum termasuk definisi Preprocessor yang digunakan (SDK yang digunakan adalah untuk C serta C ++ dan sudah tua).
Apa yang saya tertarik lakukan adalah memiliki iterator untuk berbagai WCHAR
array dua dimensi yang berisi string teks untuk mnemonik.
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;
Pendekatan saat ini adalah dengan menggunakan templat untuk menentukan kelas proxy untuk setiap array dan kemudian memiliki kelas iterator tunggal yang dapat digunakan untuk beralih pada array tertentu dengan menggunakan objek proxy yang mewakili array.
Salinan data penduduk memori disimpan dalam objek yang menangani membaca dan menulis data penduduk memori dari / ke disk. Kelas ini, CFilePara
berisi kelas proksi templated ( MnemonicIteratorDimSize
dan sub kelas dari mana asalnya, MnemonicIteratorDimSizeBase
) dan kelas iterator MnemonicIterator
,.
Objek proxy yang dibuat dilampirkan ke objek iterator yang mengakses informasi yang diperlukan melalui antarmuka yang dijelaskan oleh kelas dasar dari mana semua kelas proxy diturunkan. Hasilnya adalah memiliki satu jenis kelas iterator yang dapat digunakan dengan beberapa kelas proxy yang berbeda karena semua kelas proxy yang berbeda mengekspos antarmuka yang sama, antarmuka kelas basis proxy.
Hal pertama adalah membuat seperangkat pengidentifikasi yang akan diberikan kepada pabrik kelas untuk menghasilkan objek proxy spesifik untuk jenis mnemonik tersebut. Pengidentifikasi ini digunakan sebagai bagian dari antarmuka pengguna untuk mengidentifikasi data penyediaan tertentu yang ingin dilihat pengguna dan mungkin dimodifikasi.
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;
Kelas Proksi
Kelas proxy templated dan kelas dasarnya adalah sebagai berikut. Saya perlu mengakomodasi beberapa jenis wchar_t
array string teks. Array dua dimensi memiliki jumlah mnemonik yang berbeda, tergantung pada jenis (tujuan) mnemonik dan tipe mnemonik yang berbeda memiliki panjang maksimum yang berbeda, bervariasi antara lima karakter teks dan dua puluh karakter teks. Templat untuk kelas proksi turunan sangat cocok dengan templat yang membutuhkan jumlah karakter maksimum di setiap mnemonik. Setelah objek proxy dibuat, kami kemudian menggunakan SetRange()
metode untuk menentukan array mnemonic aktual dan jangkauannya.
// 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;
}
};
Kelas Iterator
Kelas iterator itu sendiri adalah sebagai berikut. Kelas ini hanya menyediakan fungsionalitas iterator maju dasar yang diperlukan saat ini. Namun saya berharap ini akan berubah atau diperpanjang ketika saya membutuhkan sesuatu tambahan darinya.
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
};
Pabrik objek proxy menentukan objek mana yang akan dibuat berdasarkan pengidentifikasi mnemonik. Objek proxy dibuat dan penunjuk yang dikembalikan adalah tipe kelas dasar standar sehingga memiliki antarmuka yang seragam terlepas dari bagian mnemonik mana yang sedang diakses. The SetRange()
metode yang digunakan untuk menentukan ke objek proxy elemen array tertentu proxy mewakili dan berbagai elemen array.
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;
}
Menggunakan Kelas Proxy dan Iterator
Kelas proxy dan iteratornya digunakan seperti yang ditunjukkan pada loop berikut untuk mengisi CListCtrl
objek dengan daftar mnemonik. Saya menggunakan std::unique_ptr
sehingga ketika kelas proxy saya tidak lagi diperlukan dan std::unique_ptr
keluar dari ruang lingkup, memori akan dibersihkan.
Apa yang dilakukan kode sumber ini adalah membuat objek proxy untuk array di dalamnya struct
yang sesuai dengan pengidentifikasi mnemonik yang ditentukan. Itu kemudian menciptakan iterator untuk objek itu, menggunakan rentang for
untuk mengisi CListCtrl
kontrol dan kemudian membersihkan. Ini semua adalah wchar_t
string teks mentah yang mungkin persis jumlah elemen array sehingga kami menyalin string ke buffer sementara untuk memastikan bahwa teks tersebut dihentikan nol.
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++;
}