मैं कई अलग-अलग पाठ सरणियों पर पुनरावृति करने में सक्षम होने की समस्या को हल करने की कोशिश कर रहा था, जिनमें से सभी को एक मेमोरी रेजिडेंट डेटाबेस के भीतर संग्रहीत किया जाता है यह एक बड़ा है struct
।
निम्नलिखित MFC परीक्षण अनुप्रयोग पर Visual Studio 2017 सामुदायिक संस्करण का उपयोग करके काम किया गया था। मैं इसे एक उदाहरण के रूप में शामिल कर रहा हूं क्योंकि यह पोस्टिंग कई में से एक थी जो मैंने पूरी की, जो कुछ मदद प्रदान करती थी, अभी भी मेरी जरूरतों के लिए अपर्याप्त थी।
struct
युक्त स्मृति निवासी डेटा निम्नलिखित की तरह कुछ देखा। मैंने अधिकांश तत्वों को संक्षिप्तता के लिए हटा दिया है और इसमें प्रयुक्त प्रीप्रोसेसर डिफाइन को भी शामिल नहीं किया है (उपयोग में एसडीके सी के साथ-साथ सी ++ और पुराना है)।
मुझे जो करने में दिलचस्पी थी, वह विभिन्न WCHAR
दो आयामी सरणियों के लिए पुनरावृत्तियां कर रहा था जिसमें पाठविज्ञान के लिए पाठ तार शामिल थे।
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
पाठ स्ट्रिंग सरणियों को समायोजित करने की आवश्यकता थी । दो आयामी सरणियों में अलग-अलग संख्याओं की संज्ञाएं थीं, जो कि मेनेमोनिक के प्रकार (उद्देश्य) पर निर्भर करती हैं और विभिन्न प्रकार की वर्णव्यवस्था अलग-अलग अधिकतम लंबाई की होती हैं, जो पांच पाठ पात्रों और बीस पाठ पात्रों के बीच भिन्न होती हैं। व्युत्पन्न छद्म वर्ग के लिए टेम्प्लेट एक प्राकृतिक फिट था, जिसमें प्रत्येक मेनेमिक में अधिकतम संख्या में वर्णों की आवश्यकता होती थी। प्रॉक्सी ऑब्जेक्ट बनने के बाद, हम तब 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
};
प्रॉक्सी ऑब्जेक्ट फैक्ट्री निर्धारित करती है कि एमनेमिक पहचानकर्ता के आधार पर कौन सी वस्तु बनाई जाए। प्रॉक्सी ऑब्जेक्ट बनाया गया है और पॉइंटर लौटाया गया है, मानक बेस क्लास प्रकार है, ताकि एक समान इंटरफ़ेस हो, चाहे अलग-अलग mnemonic वर्गों तक पहुँचा जा रहा हो। 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
जिसके भीतर निर्दिष्ट mnemonic पहचानकर्ता से मेल खाती है। यह तब उस वस्तु के लिए एक पुनरावृत्त बनाता है, नियंत्रण 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++;
}