التعامل مع تحذير C ++ "تهيئته ولكن لم يتم الرجوع إليه" لتدمير مساعدي النطاق؟

StackOverflow https://stackoverflow.com/questions/219770

سؤال

في Visual Studio ، غالبًا ما أستخدم الكائنات فقط لأغراض RAII. فمثلا:

ScopeGuard close_guard = MakeGuard( &close_file, file );

الغرض كله من Close_guard هو التأكد من أن الملف سيتم إغلاقه عند مخرج الوظيفة ، ولا يتم استخدامه في أي مكان آخر. ومع ذلك ، فإن Visual Studio يعطيني تحذيرًا "تتم تهيئة المتغير المحلي ولكن لم يتم الرجوع إليه". أريد إيقاف هذا التحذير لهذه الحالة المحددة.

كيف تتعامل مع هذا النوع من المواقف؟ يعتقد Visual Studio أن هذا الكائن عديم الفائدة ، لكن هذا خطأ لأنه يحتوي على مدمرة غير تافهة.

لا أريد استخدام أ #pragma تحذير التوجيه لهذا لأنه سيوقف هذا التحذير حتى لأسباب مشروعة.

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

المحلول

طريقة 1: استخدم ال #pragma warning التوجيه.

#pragma warning يسمح بالتعديل الانتقائي لسلوك رسائل تحذير البرمجيات.

#pragma warning( push )
#pragma warning( disable : 4705 ) // replace 4705 with warning number

ScopeGuard close_guard = MakeGuard( &close_file, file );

#pragma warning( pop )

يحفظ هذا الرمز حالة التحذير الحالية ، ثم يعطل التحذير من رمز تحذير محدد ثم يعيد آخر حالة تحذير محفوظة.

الطريقة 2: استخدم حلًا مثل ما يلي. سيكون Visual Studio سعيدًا وكذلك أنت. يتم استخدام هذا الحل في العديد من عينات Microsoft وكذلك في مشاريع أخرى.

ScopeGuard close_guard = MakeGuard( &close_file, file );
close_guard;

أو يمكنك إنشاء ملف #define لتوحيد التحذير.

#define UNUSED_VAR(VAR) VAR
...
ScopeGuard close_guard = MakeGuard( &close_file, file );
UNUSED_VAR(close_guard);

صرح بعض المستخدمين بأن الكود المقدم لن يعمل لأن ScopeGuard هو typedef. هذا الافتراض خاطئ.

http://www.ddj.com/cpp/184403758

وفقًا لمعيار C ++ ، فإن المرجع الذي تم تهيئته بقيمة مؤقتة يجعل تلك القيمة المؤقتة مباشرة لعمر المرجع نفسه.

نصائح أخرى

إذا كان للكائن الخاص بك مدمرة غير تافهة ، فيجب على Visual Studio ليس تعطيك هذا التحذير. لا يولد الرمز التالي أي تحذيرات في VS2005 مع تحذيرات تحولت إلى أعلى (/W4):


class Test
{
public:
    ~Test(void) { printf("destructor\n"); }
};

Test foo(void) { return Test(); }

int main(void)
{
    Test t = foo();
    printf("moo\n");

    return 0;
}

التعليق على المدمر يعطي تحذيرا. الرمز كما هو لا.

نحن نستخدم:

static_cast<void>(close_guard);

للمتغيرات التي يشكو المترجم.

في بعض ملفات رأس VC ++ ، تحدد MS الماكرو:

#define UNUSED(x) x

تستخدم مثل:

ScopeGuard close_guard = MakeGuard( &close_file, file );
UNUSED(close_guard);

الذي يسيطر على التحذير ، وتوثيقه.

سأستخدم الماكرو على طول هذه الحالة:

#define SCOPE_GUARD(guard, fn, param) \
    ScopeGuard guard = MakeGuard(fn, param); \
    static_cast<void>(guard)

الآن رمز الخاص بك جميل وقصير:

SCOPE_GUARD(g1, &file_close, file1);
SCOPE_GUARD(g2, &file_close, file2);

ميزة واحدة من هذا النهج هي أنه في وقت لاحق يمكنك إضافة __LINE__, __func__ الخ لتسجيل إجراءات الحرس في وقت لاحق إذا لزم الأمر.

حسنًا ، في هذه الحالة ، يعد ScopeGuard في الواقع typedef إلى نوع مرجعي. هذا لن يعمل للأسف.

ألا يعني هذا أن حارس ScopeGuard بأكمله لا يعمل ، لأنه في هذه الحالة لن يتم استدعاء المدمر ؟؟؟

يمكنك تحديد تحذير #Pragma حول هذا السطر من الكود فقط باستخدام

#pragma warning(push)
#pragma warning(disable:XXXX)
your code here;
#pragma warning(pop)

أو

#pragma warning(disable:XXXX)
your code here;
#pragma warning(default:XXXX)

تستطيع ايضا استخذام UNREFERENCED_PARAMETER(close_guard); بعد سطر الكود أعلاه.

أعتقد في الممارسة العملية ، سأذهب مع تعطيل #Pragma ... أو "غير مستخدم". ومع ذلك ، كقاعدة رئيسية ، يجب أن يظل الكود نظيفًا من التحذيرات حتى على حساب بعض الحجم الإضافي. يجب أن يتم تجميعها في العديد من المترجمين المختلفين على منصات مختلفة وأنظمة تشغيل دون تحذيرات. إذا لم يحدث ذلك ، يجب أن يكون الرمز ثابتًا بحيث يحدث. الحفاظ على الكود الذي يولد تحذيرات على مستوى GCC -Wall ليس فكرة جيدة.

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

حاول إضافة "متقلبة" إلى إعلان ScopeGuard.

أستخدم منشور Smink أعلاه ولا بد فقط لأضيف أنني ألصق تعليقًا بجوار #Define Gay // المستخدمة لقمع التحذير [رقم التحذير] في Visual Studio

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

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

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