حذف كائنات من النوع غير المكتمل
-
29-09-2019 - |
سؤال
هذا واحد جعلني أفكر:
class X;
void foo(X* p)
{
delete p;
}
كيف يمكننا delete p
إذا لم نعرف حتى ما إذا كان X
لديه Destructor المرئي؟ G ++ 4.5.1 يعطي ثلاث تحذيرات:
warning: possible problem detected in invocation of delete operator: warning: 'p' has incomplete type warning: forward declaration of 'struct X'
ثم تقول:
ملاحظة: لن يتم استدعاء Destructor ولا المشغل الخاص بالفئة ، حتى لو تم إعلانه عند تعريف الفصل.
واو ... هل المترجمون مطلوبون لتشخيص هذا الموقف مثل G ++ يفعل؟ أم أنه سلوك غير محدد؟
المحلول
من المعيار [expr.delete]:
إذا كان الكائن الذي يتم حذفه لديه نوع فئة غير مكتمل عند نقطة الحذف وكان الفئة الكاملة لها مدمرة غير تافهة أو وظيفة تخصيص التخصيص ، فإن السلوك غير محدد.
لذلك ، فهو UB إذا كانت هناك أشياء غير تافهة ، ولا بأس إذا لم يكن هناك. التحذيرات ليست ضرورية لـ UB.
نصائح أخرى
إنه سلوك غير محدد.
ومع ذلك ، يمكنك إجراء فحص المترجم لأنواع غير مكتملة ، مثل التعزيز:
// verify that types are complete for increased safety
template<class T> inline void checked_delete(T * x)
{
// intentionally complex - simplification causes regressions
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete x;
}
التقديم sizeof
يجب أن يؤدي إلى نوع غير مكتمل إلى خطأ ، وأفترض ما إذا كان ذلك يمر مع بعض التحويلات البرمجية ، فإن مجموعة من الحجم السلبي ستؤدي إلى خطأ.
إنه سلوك غير محدد ، و gotcha المشتركة عند تنفيذ نمط PIMPL. على حد علمي ، لا يوجد ببساطة أي شيء مثل تحذير من أن المترجم مطلوب لإبعاده. التحذيرات اختيارية. إنهم موجودون لأن كاتب التحويل البرمجي يعتقد أنهم سيكونون مفيدين.