سؤال

جئت عبر هذا المقال كتبه Andrei Alexandrescu وPetru Marginean منذ سنوات عديدة، والذي يقدم ويناقش فئة أدوات مساعدة تسمى ScopeGuard لكتابة تعليمات برمجية آمنة للاستثناء.أرغب في معرفة ما إذا كان التشفير باستخدام هذه الكائنات يؤدي حقًا إلى تعليمة برمجية أفضل أو إذا كان يؤدي إلى تشويش معالجة الأخطاء، حيث ربما يتم تقديم رد اتصال الحارس بشكل أفضل في كتلة الالتقاط؟هل لدى أي شخص أي خبرة في استخدام هذه في رمز الإنتاج الفعلي؟

هل كانت مفيدة؟

المحلول

إنه بالتأكيد يحسن التعليمات البرمجية الخاصة بك.ادعاءك الذي تم صياغته مبدئيًا، بأنه غامض وأن هذا الرمز يستحق من أ catch block ببساطة غير صحيح في C++ لأن RAII هو مصطلح راسخ.معالجة الموارد في C++ يكون يتم ذلك عن طريق الحصول على الموارد وجمع البيانات المهملة عن طريق استدعاءات التدمير الضمنية.

ومن ناحية أخرى صريحة catch قد تؤدي الكتل إلى تضخم التعليمات البرمجية وإدخال أخطاء طفيفة لأن تدفق التعليمات البرمجية يصبح أكثر تعقيدًا ويجب أن تتم معالجة الموارد بشكل صريح.

راي (بما في ذلك ScopeGuards) ليست تقنية غامضة في C++ ولكنها أفضل الممارسات الراسخة.

نصائح أخرى

نعم.

إذا كان هناك جزء واحد من كود C++ يمكنني أن أوصي به كل مبرمج C++ يقضي 10 دقائق في التعلم، فهو ScopeGuard (الآن جزء من البرنامج المتاح مجانًا مكتبة لوكي).

قررت أن أحاول استخدام إصدار (معدل قليلاً) من ScopeGuard لبرنامج Win32 GUI الصغير الذي كنت أعمل عليه.كما تعلم، يحتوي Win32 على العديد من أنواع الموارد المختلفة التي يجب إغلاقها بطرق مختلفة (على سبيل المثال.عادة ما تكون مقابض النواة مغلقة CloseHandle(), ، جي دي آي BeginPaint() يجب أن يقترن مع EndPaint(), ، وما إلى ذلك) لقد استخدمت ScopeGuard مع كل هذه الموارد، وكذلك لتخصيص المخازن المؤقتة للعمل معها new (على سبيل المثاللتحويلات مجموعة الأحرف من/إلى Unicode).

ما أدهشني هو كم أقصر كان البرنامج. في الأساس، إنه مربح للجانبين:يصبح الكود الخاص بك أقصر وأكثر قوة في نفس الوقت.تغييرات الكود المستقبلية لا يمكن تسريب أي شيء.إنهم لا يستطيعون ذلك.كم ذلك رائع؟

غالبًا ما أستخدمه لحماية استخدام الذاكرة، والأشياء التي تحتاج إلى تحرير والتي تم إرجاعها من نظام التشغيل.على سبيل المثال:

DATA_BLOB blobIn, blobOut;
blobIn.pbData=const_cast<BYTE*>(data);
blobIn.cbData=length;

CryptUnprotectData(&blobIn, NULL, NULL, NULL, NULL, CRYPTPROTECT_UI_FORBIDDEN, &blobOut);
Guard guardBlob=guardFn(::LocalFree, blobOut.pbData);
// do stuff with blobOut.pbData

لم أستخدم هذا القالب بالتحديد ولكني استخدمت شيئًا مشابهًا من قبل.نعم، إنه يؤدي إلى تعليمات برمجية أكثر وضوحًا بالمقارنة مع تعليمات برمجية قوية بنفس القدر يتم تنفيذها بطرق مختلفة.

أعتقد أن الإجابات المذكورة أعلاه تفتقر إلى ملاحظة مهمة واحدة.وكما أشار آخرون، يمكنك استخدام ScopeGuard من أجل تحرير الموارد المخصصة بشكل مستقل عن الفشل (الاستثناء).ولكن قد لا يكون هذا هو الشيء الوحيد الذي قد ترغب في استخدام حارس النطاق من أجله.في الواقع، تستخدم الأمثلة الموجودة في المقالة المرتبطة ScopeGuard لغرض مختلف:التحويلات.باختصار، قد يكون من المفيد إذا كان لديك كائنات متعددة (حتى لو كانت هذه الكائنات تستخدم RAII بشكل صحيح) والتي تحتاج إلى الاحتفاظ بها في حالة مرتبطة بطريقة ما.إذا أدى تغيير حالة أي من هذه الكائنات إلى استثناء (والذي، كما أفترض، يعني عادة أن حالته لم تتغير) فيجب التراجع عن جميع التغييرات المطبقة بالفعل.يؤدي هذا إلى إنشاء مجموعة المشاكل الخاصة به (ماذا لو فشل التراجع أيضًا؟).يمكنك محاولة طرح فصلك الخاص الذي يدير مثل هذه الكائنات المترابطة، ولكن مع زيادة عدد هذه الكائنات، سيصبح الأمر فوضويًا ومن المحتمل أن تعود إلى الاستخدام ScopeGuard داخليا على أية حال.

نعم.

لقد كان من المهم جدًا في C++ أنه حتى بناء جملة خاص به في D:

void somefunction() {
    writeln("function enter");
    // c++ has similar constructs but not in syntax level
    scope(exit) writeln("function exit");

    // do what ever you do, you never miss the function exit output
}

يجب أن أقول، لا، لا، لا.تساعد الإجابات هنا في توضيح سبب كونها فكرة فظيعة حقًا.يجب أن تتم معالجة الموارد من خلال فئات قابلة لإعادة الاستخدام.الشيء الوحيد الذي حققوه باستخدام حارس النطاق هو انتهاك DRY up the wazoo وتكرار كود تحرير الموارد الخاص بهم في جميع أنحاء قاعدة التعليمات البرمجية الخاصة بهم، بدلاً من كتابة فئة واحدة للتعامل مع المورد ثم هذا كل شيء، للمجموعة بأكملها.

لو حراس النطاق لديهم أي استخدامات فعلية، كما هو الحال في التعامل مع الموارد لا واحد منهم.إنها أقل شأناً إلى حد كبير من RAII العادي في هذه الحالة، نظرًا لأن RAII تم إلغاء تكراره وتلقائيًا، كما أن حراس النطاق عبارة عن تكرار يدوي للكود أو إفلاسه.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top