struct
ผมพยายามที่จะแก้ปัญหาของความสามารถในการย้ำผ่านอาร์เรย์หลายข้อความที่แตกต่างกันซึ่งทั้งหมดจะถูกเก็บไว้ภายในฐานข้อมูลหน่วยความจำที่มีถิ่นที่อยู่เป็นที่มีขนาดใหญ่
ต่อไปนี้เป็นผลงานโดยใช้ Visual Studio 2017 Community Edition ในแอปพลิเคชันทดสอบ MFC ฉันรวมนี่เป็นตัวอย่างเนื่องจากการโพสต์นี้เป็นหนึ่งในหลาย ๆ ที่ฉันวิ่งข้ามที่ให้ความช่วยเหลือ แต่ก็ยังไม่เพียงพอสำหรับความต้องการของฉัน
ข้อมูลstruct
ที่อยู่ในหน่วยความจำประกอบด้วยข้อมูลดังต่อไปนี้ ฉันได้ลบองค์ประกอบส่วนใหญ่เพื่อประโยชน์ของความกะทัดรัดและยังไม่รวมถึงการกำหนด Preprocessor ที่ใช้ (SDK ที่ใช้สำหรับ C และ C ++ และเก่า)
สิ่งที่ฉันสนใจทำคือมีตัววนซ้ำสำหรับ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
) และชั้น iterator 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;
ระดับพร็อกซี่
คลาสพร็อกซี templated และคลาสพื้นฐานมีดังนี้ ฉันจำเป็นต้องรองรับอาเรย์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;
}
};
The Iterator Class
คลาสตัววนซ้ำตัวเองมีดังนี้ คลาสนี้จัดเตรียมฟังก์ชันการทำงานตัวส่งต่อพื้นฐานแบบพื้นฐานซึ่งเป็นสิ่งที่จำเป็นในเวลานี้ อย่างไรก็ตามฉันคาดหวังว่าสิ่งนี้จะเปลี่ยนแปลงหรือขยายออกไปเมื่อฉันต้องการอะไรเพิ่มเติมจากมัน
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;
}
การใช้ Proxy Class และ Iterator
คลาสพร็อกซีและตัววนซ้ำของมันถูกใช้ตามที่แสดงในลูปต่อไปนี้เพื่อเติมCListCtrl
วัตถุที่มีรายการช่วยในการจำ ฉันใช้std::unique_ptr
เพื่อที่เมื่อไม่จำเป็นต้องใช้พร็อกซีคลาสอีกต่อไปและไม่อยู่std::unique_ptr
ในขอบเขตหน่วยความจำจะถูกล้างออก
สิ่งที่ซอร์สโค้ดนี้ทำคือการสร้างวัตถุพร็อกซีสำหรับอาร์เรย์ภายในstruct
ซึ่งสอดคล้องกับตัวช่วยจำที่ระบุ จากนั้นจะสร้างตัววนซ้ำสำหรับวัตถุนั้นใช้ระยะห่าง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++;
}