Hepsi büyük bir bellek yerleşik veritabanı içinde saklanan birkaç farklı metin dizileri üzerinde yineleme yapabilmek sorunu çözmeye çalışıyordu struct
.
Aşağıdakiler bir MFC test uygulamasında Visual Studio 2017 Community Edition kullanılarak çalışıldı. Ben bu örnek bir örnek olarak dahil ediyorum çünkü bu yazı bazı yardım sağlanan ama yine de benim ihtiyaçları için hala yetersiz olduğunu koştum birkaç biri oldu.
struct
İçeren bellek yerleşik veri Aşağıdaki gibi bir şey görünüyordu. Ben kısaca uğruna elemanların çoğunu kaldırdım ve kullanılan Önişlemci tanımlarını da dahil etmedim (kullanılan SDK, C'nin yanı sıra C ++ içindir ve eskidir).
Yapmakla ilgilendiğim şey, WCHAR
anımsatıcılar için metin dizeleri içeren çeşitli iki boyutlu diziler için yineleyiciler kullanmaktır .
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;
Geçerli yaklaşım, dizilerin her biri için bir proxy sınıfı tanımlamak için bir şablon kullanmak ve daha sonra diziyi temsil eden bir proxy nesnesi kullanarak belirli bir dizi üzerinde yineleme yapmak için kullanılabilecek tek bir yineleyici sınıfına sahip olmaktır.
Bellek yerleşik verilerinin bir kopyası, bellek yerleşik verilerinin diske / diskten okunmasını ve yazılmasını sağlayan bir nesnede saklanır. Bu sınıf, CFilePara
geçici proxy sınıfını ( MnemonicIteratorDimSize
ve türetildiği alt sınıfı MnemonicIteratorDimSizeBase
) ve yineleyici sınıfını içerir MnemonicIterator
.
Oluşturulan proxy nesnesi, tüm proxy sınıflarının türetildiği bir temel sınıf tarafından tanımlanan bir arabirim aracılığıyla gerekli bilgilere erişen bir yineleyici nesnesine eklenir. Sonuç, farklı proxy sınıflarının hepsi aynı arabirimi, proxy temel sınıfının arabirimini ortaya çıkardığı için birkaç farklı proxy sınıfıyla kullanılabilen tek bir yineleyici sınıfına sahip olmaktır.
İlk şey, söz konusu anımsatıcı türü için belirli proxy nesnesini oluşturmak üzere bir sınıf fabrikasına sağlanacak bir dizi tanımlayıcı oluşturmaktı. Bu tanımlayıcılar, kullanıcının görmek ve muhtemelen değiştirmek istediği belirli hazırlık verilerini tanımlamak için kullanıcı arayüzünün bir parçası olarak kullanılır.
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;
Proxy Sınıfı
Şablonlu proxy sınıfı ve temel sınıfı aşağıdaki gibidir. Birkaç farklı wchar_t
metin dizesi dizisi barındırmak gerekiyordu. İki boyutlu diziler, anımsatıcının türüne (amacına) bağlı olarak farklı sayıda anımsatıcıya sahipti ve farklı anımsatıcı türleri, beş metin karakteri ve yirmi metin karakteri arasında değişen farklı maksimum uzunluklara sahipti. Türetilmiş proxy sınıfı için şablonlar, her anımsatıcıda maksimum karakter sayısı gerektiren şablona doğal bir uyum sağladı. Proxy nesnesi oluşturulduktan sonra SetRange()
, gerçek anımsatıcı diziyi ve aralığını belirtmek için yöntemi kullanırız.
// 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;
}
};
Yineleyici Sınıfı
Yineleyici sınıfının kendisi aşağıdaki gibidir. Bu sınıf, şu anda ihtiyaç duyulan tek şey temel ileri yineleyici işlevselliği sağlar. Ancak, bundan başka bir şeye ihtiyacım olduğunda bunun değişeceğini veya genişletileceğini umuyorum.
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
};
Proxy nesne fabrikası, anımsatıcı tanımlayıcısına göre hangi nesnenin oluşturulacağını belirler. Proxy nesnesi oluşturulur ve döndürülen işaretçi, farklı anımsatıcı bölümlerden hangisine erişildiğine bakılmaksızın tek tip bir arabirime sahip olacak şekilde standart temel sınıf türüdür. SetRange()
Yöntem vekil nesneye vekil temsil ettiği özel dizi elemanları ve dizi elemanlarının aralığı belirtmek için kullanılır.
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;
}
Proxy Sınıfını ve Yineleyiciyi Kullanma
Proxy sınıfı ve yineleyicisi, bir CListCtrl
nesneyi anımsatıcı listesiyle doldurmak için aşağıdaki döngüde gösterildiği gibi kullanılır . Ben kullanıyorum std::unique_ptr
vekil sınıf i değil artık ihtiyaç ve ne zaman ki std::unique_ptr
kapsam dışına gider, hafıza kadar temizlenecektir.
Bu kaynak kodun yaptığı, içinde struct
belirtilen anımsatıcı tanımlayıcısına karşılık gelen dizi için bir proxy nesnesi oluşturmaktır . Daha sonra bu nesne için bir yineleyici oluşturur for
, CListCtrl
kontrolü doldurmak için bir aralık kullanır ve sonra temizler. Bunların hepsi wchar_t
tam olarak dizi öğesi sayısı olabilen ham metin dizeleridir, bu nedenle metnin sıfır sonlandırıldığından emin olmak için dizeyi geçici bir ara belleğe kopyalarız.
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++;
}