سؤال

هل يوجد "شيء سيء للغاية" يمكن أن يحدث ذلك && = و || = تم استخدامه كسكر نحوي ل bool foo = foo && bar و bool foo = foo || bar?

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

المحلول

أ bool قد يكون فقط true أو false في C ++. على هذا النحو ، باستخدام &= و |= آمن نسبيًا (على الرغم من أنني لا أحب التدوين بشكل خاص). صحيح ، أنهم سيؤدون عمليات بت بدلاً من العمليات المنطقية (وبالتالي لن تكون دائرة قصيرة) ، لكن عمليات البت هذه تتبع رسم خرائط محدد جيدًا ، وهو ما يعادل فعليًا العمليات المنطقية ، طالما كلا المعاملين من النوع bool.1

على عكس ما قاله الآخرون هنا ، أ bool في C ++ يجب ألا يكون له قيمة مختلفة مثل 2. عند تعيين هذه القيمة إلى bool, ، سيتم تحويله إلى true حسب المعيار.

الطريقة الوحيدة للحصول على قيمة غير صالحة في bool باستخدام reinterpret_cast على المؤشرات:

int i = 2;
bool b = *reinterpret_cast<bool*>(&i);
b |= true; // MAY yield 3 (but doesn’t on my PC!)

ولكن نظرًا لأن هذا الرمز ينتج عنه سلوك غير محدد على أي حال ، فقد نتجاهل هذه المشكلة المحتملة بأمان في رمز C ++ المطابق.


1 من المسلم به أن هذا تحذير كبير إلى حد ما كما يوضح تعليق Angew:

bool b = true;
b &= 2; // yields `false`.

والسبب هو أن b & 2 يؤدي ترويج عدد صحيح بحيث يكون التعبير مكافئًا static_cast<int>(b) & 2, ، مما يؤدي إلى 0, ، الذي يتم تحويله مرة أخرى إلى أ bool. لذلك صحيح أن وجود operator &&= من شأنه تحسين سلامة النوع.

نصائح أخرى

&& و & لديك دلالات مختلفة: && لن يقوم بتقييم المعامل الثاني إذا كان المعامل الأول false. أي شيء مثل

flag = (ptr != NULL) && (ptr->member > 3);

آمن ، لكن

flag = (ptr != NULL) & (ptr->member > 3);

ليس كذلك ، على الرغم من أن كلا المعاملين من النوع bool.

وينطبق الشيء نفسه على &= و |=:

flag = CheckFileExists();
flag = flag && CheckFileReadable();
flag = flag && CheckFileContents();

سوف يتصرف بشكل مختلف عن:

flag = CheckFileExists();
flag &= CheckFileReadable();
flag &= CheckFileContents();

اجابة قصيرة

جميع المشغلين +=, -=, *=, /=, &=, |=... هي الحساب وتوفير نفس التوقع:

x &= foo()  // We expect foo() be called whatever the value of x

ومع ذلك ، المشغلين &&= و ||= سيكون منطقيًا ، وقد يكون هؤلاء المشغلين معرضين للخطأ لأن العديد من المطورين يتوقعون foo() يتم الاتصال به دائمًا في x &&= foo().

bool x;
// ...
x &&= foo();           // Many developers might be confused
x = x && foo();        // Still confusing but correct
x = x ? foo() : x;     // Understandable
x = x ? foo() : false; // Understandable
if (x) x = foo();      // Obvious
  • هل نحتاج حقًا إلى جعل C/C ++ أكثر تعقيدًا للحصول على اختصار ل x = x && foo()?

  • هل نريد حقًا أن نتعامل مع المزيد من البيان الخفي x = x && foo()?
    أو هل نريد كتابة رمز ذي معنى مثل if (x) x = foo();?


اجابة طويلة

مثال على &&=

إذا &&= كان المشغل متاحًا ، ثم هذا الرمز:

bool ok = true; //becomes false when at least a function returns false
ok &&= f1();
ok &&= f2(); //we may expect f2() is called whatever the f1() returned value

يعادل:

bool ok = true;
if (ok) ok = f1();
if (ok) ok = f2(); //f2() is called only when f1() returns true

هذا الرمز الأول هو معرض للخطأ لأن العديد من المطورين سيفكرون f2() يطلق عليه دائما مهما كان f1() القيمة التي تم إرجاعها. إنه مثل الكتابة bool ok = f1() && f2(); أين f2() يسمى فقط متى f1() عائدات true.

  • إذا كان المطور يريد بالفعل f2() ليتم استدعاؤها فقط عندما f1() عائدات true, ، وبالتالي فإن الرمز الثاني أعلاه أقل عرضة للخطأ.
  • آخر (يريد المطور f2() ليتم استدعاؤه دائمًا) ، &= كافي:

مثال على &=

bool ok = true;
ok &= f1();
ok &= f2(); //f2() always called whatever the f1() returned value

علاوة على ذلك ، من الأسهل على برنامج التحويل البرمجي تحسين هذا الرمز أعلاه من تلك الموجودة أدناه:

bool ok = true;
if (!f1())  ok = false;
if (!f2())  ok = false;  //f2() always called

قارن && و &

قد نتساءل ما إذا كان المشغلون && و & إعطاء نفس النتيجة عند تطبيقها bool القيم؟

دعنا نتحقق من استخدام رمز C ++ التالي:

#include <iostream>

void test (int testnumber, bool a, bool b)
{
   std::cout << testnumber <<") a="<< a <<" and b="<< b <<"\n"
                "a && b = "<< (a && b)  <<"\n"
                "a &  b = "<< (a &  b)  <<"\n"
                "======================"  "\n";
}

int main ()
{
    test (1, true,  true);
    test (2, true,  false);
    test (3, false, false);
    test (4, false, true);
}

انتاج:

1) a=1 and b=1
a && b = 1
a &  b = 1
======================
2) a=1 and b=0
a && b = 0
a &  b = 0
======================
3) a=0 and b=0
a && b = 0
a &  b = 0
======================
4) a=0 and b=1
a && b = 0
a &  b = 0
======================

استنتاج

وبالتالي نعم يمكننا استبدال && بواسطة & إلى عن على bool القيم ؛-)
لذلك أفضل استخدام &= بدلاً من &&=.
يمكن أن نعتبر &&= كما لا طائل منه للملاءات.

الشيء نفسه بالنسبة ل ||=

المشغل أو العامل |= هو أيضا أقل معرض للخطأ من ||=

إذا كان المطور يريد f2() يتم استدعاؤها فقط عندما f1() عائدات false, ، بدلاً من:

bool ok = false;
ok ||= f1();
ok ||= f2(); //f2() is called only when f1() returns false
ok ||= f3(); //f3() is called only when f1() or f2() return false
ok ||= f4(); //f4() is called only when ...

أنصح بديل أكثر قابلية للفهم:

bool ok = false;
if (!ok) ok = f1();
if (!ok) ok = f2();
if (!ok) ok = f3();
if (!ok) ok = f4();
// no comment required here (code is enough understandable)

أو إذا كنت تفضل كل شيء في سطر واحد نمط:

// this comment is required to explain to developers that 
// f2() is called only when f1() returns false, and so on...
bool ok = f1() || f2() || f3() || f4();
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top