أي شيء خاطئ في هذا التصميم لتهيئة المصفوفة في DLL؟
-
29-09-2019 - |
سؤال
لنفترض أن لدينا DLL ويجب أن يكون هناك صفيف مخزّن عالميًا فيه سيتم تصديره ، والشيء هو أننا نريد تهيئته من خلال قراءة بعض المحتوى من ملف ، لذلك أنا شخصياً لا أجد نفسي طريقة أخرى غير وضع طريقة أخرى في البنية لتكون قادرة على التهيئة باستخدام مُنشئ:
struct Construction{
public:
Construction(){
//do the initialization thing and read the needed data from the file
}
SomeType sTArray[100];
};
__declspec(dllexport) Construction obj();
الآن حيث سيتم استخدامه ، يمكن للمبرمج تهيئة مرجع إليه ثم استخدام المرجع كما هو أدناه:
SomeType (&arrayRef)[100]=obj.sTArray;
الآن هل تعتقد أنني مخطئ في أي سياق؟
المحلول
نعم ، لقد قمت بإعداد نفسك لمفاجأة سيئة للغاية في مرحلة ما.
- يتم تشغيل منشئي الكائنات العالمية أثناء بدء تشغيل C -Runtime لـ DLL.
- يعمل رمز بدء التشغيل C أثناء DLLMAIN.
- أثناء dllmain ، أنت تمسك قفل محمل DLL.
- قد يتضمن مُنشئ الكائنات مكالمات لـ Win32 API التي تقوم بتحميل نظام DLL الآخر.
- تتجه لتحميل DLL آخر أثناء حمل قفل DLL Loader بالفعل إلى موت سريع لعملية الخاص بك.
أوصي بأن تتوقف عن تهيئة الصفيف حتى أول محاولة للوصول إليها ، الأمر الذي سيتطلب منك فضح المصفوفة بشكل غير مباشر نتيجة لدعوة الوظيفة:
struct Construction{
public:
Construction() : bInit(false) {};
SomeType* GetArray()
{
if(!bInit)
{
//do the initialization thing and read the needed data from the file
bInit = true;
}
return sTArray;
};
private:
SomeType sTArray[100];
bool bInit;
};
__declspec(dllexport) Construction obj();
بالطبع ، يجب تقسيم هذا إلى ملفات منفصلة وتنفيذ.
نصائح أخرى
نظرًا لأن CRT في DLL وفي القابل للتنفيذ قد يكون مختلفًا ، يجب عليك توفير Construction
مع release
الطريقة التي ستحذف كائن مخصص. وبهذه الطريقة ، ستضمن استدعاء وظيفة التخصيص من CRT المناسب. كما تحتاج إلى العودة Construction
بواسطة مؤشر لاستبعاد عمليات النسخ. يوضح الرمز التالي الطريقة التي يمكن بها تنفيذها:
// DLL export header
struct IConstruction {
protected:
virtual ~IConstruction() {}
public:
virtual void release() =0;
virtual SomeType& get_array() =0;
};
__declspec(dllexport) IConstruction* obj();
-
// DLL implementation
struct Construction : public IConstruction {
SomeType sTArray[100];
Construction() { /* do initialization */ }
virtual void release() { delete this; }
virtual SomeType& get_array() { return sTArray; }
virtual ~Construction() { /* do clean up */ }
};
IConstruction* obj() { return new Construction; }