it-swarm.dev

هل يمكنني استخدام إذا (المؤشر) بدلاً من إذا (المؤشر! = NULL)؟

هل من الآمن التحقق من مؤشر لعدم NULL بكتابة ببساطة if(pointer) أو هل يجب علي استخدام if(pointer != NULL)؟

157
danijar

يمكنك؛ يتم تحويل المؤشر الفارغ ضمنيًا إلى خطأ منطقي بينما يتم تحويل المؤشرات غير الفارغة إلى صواب. من المعيار C++ 11 ، قسم on التحويلات المنطقية:

يمكن تحويل قيمة القيمة الحسابية ، أو التعداد غير المفصول ، أو المؤشر ، أو المؤشر إلى نوع العضو إلى قيمة من النوع bool. يتم تحويل قيمة صفرية أو قيمة مؤشر فارغة أو قيمة مؤشر عضو فارغ إلى false؛ يتم تحويل أي قيمة أخرى إلى true. يمكن تحويل قيمة من النوع std::nullptr_t إلى قيمة من النوع bool؛ القيمة الناتجة هي false.

173
Joni

نعم ، يمكنك ذلك.

  • يتم تحويل مؤشر فارغة إلى false ضمنيًا
  • يتم تحويل مؤشر غير فارغة إلى true.

هذا جزء من التحويل القياسي C++ ، والذي يقع في التحويل المنطقي جملة:

§ 4.12 تحويلات منطقية

يمكن تحويل قيمة القيمة الحسابية أو التعداد غير المفصول و المؤشر أو المؤشر إلى نوع العضو إلى قيمة من النوع المنطقي. يتم تحويل قيمة صفر أو قيمة مؤشر فارغة أو قيمة مؤشر عضو فارغة إلى false؛ يتم تحويل أي قيمة أخرى إلى صحيح. a prvalue of type std :: nullptr_t يمكن تحويلها إلى prvalue من type bool؛ القيمة الناتجة غير صحيحة.

37
billz

نعم تستطيع. في الحقيقة ، أفضل استخدام if(pointer) لأنه من الأسهل القراءة والكتابة بمجرد التعود عليها.

لاحظ أيضًا أن C++ 11 قدمت nullptr والذي يفضل على NULL.

29
Yu Hao

تم الإجابة على السؤال ، لكن أود إضافة نقاطي.

سأفضل دائمًا if(pointer) بدلاً من if(pointer != NULL) و if(!pointer) بدلاً من if(pointer == NULL):

  • انها بسيطة وصغيرة
  • فرص أقل لكتابة رمز عربات التي تجرها الدواب ، لنفترض إذا أخطأت في التحقق من عامل تحقق المساواة == مع =
    if(pointer == NULL) يمكن أن يكون هناك خطأ إملائي if(pointer = NULL) لذلك سأتجنب ذلك ، والأفضل هو if(pointer).
    (كما اقترحت بعض حالة يودا في إجابة واحدة ، ولكن هذا أمر مختلف)

  • وبالمثل بالنسبة لـ while (node != NULL && node->data == key) ، سأكتب ببساطة while (node && node->data == key) التي تكون أكثر وضوحًا بالنسبة لي (توضح ذلك باستخدام ماس كهربائى).

  • (قد يكون سببًا غبيًا) نظرًا لأن NULL ماكرو ، فإذا افترضنا أن أحدهم أعيد تعريفه عن طريق الخطأ مع قيمة أخرى.
12
Grijesh Chauhan

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

 enter image description here 

9
Minqi Pan

نعم تستطيع. لقد تم توريث القدرة على مقارنة القيم بالأصفار بشكل ضمني من C ، وهناك في جميع إصدارات C++. يمكنك أيضًا استخدام if (!pointer) للتحقق من مؤشرات NULL.

8
dasblinkenlight

حالات الاستخدام ذات الصلة لمؤشرات فارغة هي

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

    Derived* derived_ptr = dynamic_cast<Derived*>(base_ptr);
    if(derived_ptr != nullptr) { ... }
    

    (أو ، بشكل مفضل ، auto derived_ptr = ...). الآن ، هذا أمر سيء ، لأنه يترك المؤشر (ربما يكون غير صالح ، أي لاشيء) المشتق خارج نطاق كتلة الحماية if. هذا ليس ضروريًا ، لأن C++ يتيح لك تقديم متغيرات قابلة للتحويل المنطقي داخل if- شرط :

    if(auto derived_ptr = dynamic_cast<Derived*>(base_ptr)) { ... }
    

    وهو ليس أقصر وأكثر أمانًا للنطاق ، بل هو أيضًا أكثر وضوحًا في نيته: عند التحقق من عدم وجود شرط في حالة منفصلة ، يتساءل القارئ "حسنًا ، لذلك يجب ألا يكون derived_ptr فارغًا هنا ... حسنًا ، لماذا هل ستكون خالية؟ " بينما تقول النسخة المؤلفة من سطر واحد بوضوح "إذا كان بإمكانك إرسال كود base_ptr بأمان إلى Derived* ، فاستخدمه من أجل ...".

    يعمل نفس الشيء أيضًا مع أي عملية أخرى محتملة للفشل تُرجع مؤشرًا ، على الرغم من أن IMO يجب عليك عمومًا تجنب ذلك: من الأفضل استخدام شيء مثل boost::optional كـ "الحاوية" لنتائج عمليات فاشلة محتملة ، بدلاً من المؤشرات.

لذلك ، إذا كان يجب دائمًا كتابة حالة الاستخدام الرئيسية للمؤشرات الفارغة في صيغة مختلفة من النمط الضمني ، فأنا أقول أنه من الجيد لأسباب الاتساق أن تستخدم دائمًا استخدم هذا النمط ، أي أنني أدافع عن if(ptr) over if(ptr!=nullptr).


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

أفضل بكثير: ضع في اعتبارك على الفور جميع الحالات التي قد تواجهها. ثم التصرف وفقا لذلك. هاسكل:

makeSoupOf :: Foodstuff -> Liquid
makeSoupOf [email protected](Potato{..}) = mash (boil p) <> water
makeSoupOf vegetable
 | isSoft vegetable  = squeeze vegetable <> salt
makeSoupOf stuff  = boil (throwIn (water<>salt) stuff)

لدى Haskell أيضًا أدوات خاصة عندما يكون هناك بالفعل احتمال كبير للفشل (بالإضافة إلى مجموعة كاملة من الأشياء الأخرى): monads. ولكن هذا ليس هو المكان المناسب لشرح هؤلاء.

⟨/ advert⟩

2
leftaroundabout

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

0
darshandzend

نعم بالطبع! في الواقع ، الكتابة إذا كان (المؤشر) هو وسيلة أكثر ملاءمة للكتابة بدلاً من إذا (المؤشر! = NULL) للأسباب التالية: 1. يسهل تصحيحها 2. يسهل فهمها 3. إذا تم بالصدفة ، يتم تحديد قيمة NULL ، ثم أيضا سوف رمز لا تعطل

0
Palak Jain