سؤال

هذا واحد جعلني أفكر:

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. على حد علمي ، لا يوجد ببساطة أي شيء مثل تحذير من أن المترجم مطلوب لإبعاده. التحذيرات اختيارية. إنهم موجودون لأن كاتب التحويل البرمجي يعتقد أنهم سيكونون مفيدين.

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