هل من الممكن أن الخروج قبل الوقت في C++, إذا كان إنهاء حالة التوصل إلى ذلك ؟

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

  •  03-07-2019
  •  | 
  •  

سؤال

أريد أن أعرف إذا كان من الممكن أن تنتهي حلقة في C++ عندما تنتهي حالة (مختلفة من reacheing حق عدد من التكرارات) هو التحقق منها.على سبيل المثال:

for (int i = 0; i < maxi; ++i)
    for (int j = 0; j < maxj; ++j)
        // But if i == 4 < maxi AND j == 3 < maxj, 
        // then jump out of the two nested loops.

أنا أعرف أن هذا ممكن في بيرل مع التسمية أو التسمية الأخيرة مكالمات وصفت كتل ، هل من الممكن أن تفعل ذلك في C++ أو ينبغي أن تستخدم أثناء الحلقة ؟

شكرا لك.

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

المحلول

ويمكنك استخدام الكلمة return: نقل حلقة متداخلة إلى روتين، استدعاء روتين لتشغيل الحلقات المتداخلة، و "العودة" من روتين للخروج [كل] الحلقات

.

نصائح أخرى

على الرغم من "goto تعتبر ضارة" الحجج, هذا يبدو وكأنه المكان المثالي goto.هذا هو أساسا ما تقومون به في بيرل.على محمل الجد...النظر في البدائل:

إضافية الدولة المتغيرات


for (int i=0; i<maxi; ++i) {
    bool leaveLoop = false;
    for (int j=0; j<maxj; ++j) {
        if (i == 4 && j == 3) {
            leaveLoop = true;
            break; // leave the inner loop
        }
    }
    if (leaveLoop) {
        break; // leave the outside loop
    }
}

الإجازة استثناء


try {
    for (int i=0; i<maxi; ++i) {
        for (int j=0; j<maxj; ++j) {
            if (i == 4 && j == 3) {
                throw leave_loop();
            }
        }
    }
} catch (leave_loop const&) {
}

منطق معقد


int j = 0;
for (int i=0; i<maxi && !(i==4 && j==3); ++i) {
    for (j=0; j<maxj && !(i==4 && j==3); ++j) {
        // inner loop
    }
}

goto


for (int i=0; i<maxi; ++i) {
    for (int j=0; j<maxj; ++j) {
        if (i==4 && j==3) {
            goto leave_loop;
        }
    }
}
leave_loop:

هو آخر أقل وضوحا ؟ أنا لا أعتقد أنه هو.هو أي أكثر من الضعف ؟ IMHO ، والبعض الآخر تماما معرضون للخطأ و هشة مقارنة goto الإصدار.آسف أن يكون واقفا على المنبر هنا ولكن هذا هو الشيء الذي قد ازعجت لي لفترة من الوقت؛)

الشيء الوحيد الذي عليك أن تكون congnizent من أن goto والاستثناءات هي مشابهة جدا.كلاهما فتح فرصة تسرب الموارد ما لا علاج لهم الرعاية.

اسمحوا لي أن أقول هذا بشكل قاطع (ولكن بأدب ;-) ما أستطيع: على for بناء في ج-مثل اللغة ليست عن العد.

اختبار التعبير الذي يحدد ما إذا كان سيستمر يمكن أن يكون أي شيء التي هي ذات الصلة إلى الغرض من الحلقة ؛ التحديث التعبير لا يجب أن تكون "إضافة إلى مواجهة".

for (int i = 0, j = 0; i < maxi && j < maxj && i != 4 && j != 3;) {
    if (j < maxj) {
        ++j;
    } else {
        j = 0;
        ++i;
    }
}

سيكون واحد (إجراء تعسفي إلى حد ما) طريقة كتابة.

وهذه النقطة هي أنه إذا كان إنشاء الشرط هو نقطة interation ، فإنه عادة ما يكون من الممكن كتابة حلقة (باستخدام إما while أو for) بطريقة الولايات تواصل/إنهاء حالة أكثر صراحة.

(إذا كنت يمكن أن المنصب وصف ما يحدث في الواقع ، فإنه من المرجح أن أكتب شيئا لا تبدو تعسفية كما سبق.)

لا يمكنك القفز من اثنين حلقات مع واحد كسر التعليمات لكن هل يمكن استخدام goto إلى القفز من الحلقة الداخلية الخارج.

إذا غوتو المترجمة ، يعني أن هناك أقل من المنطق خلاف ذلك أعتقد أنه من المقبول تماما التعليمات البرمجية.وقد إضافية العلم المتغيرات ، أو رفع مكرر متغير من الحلقة الداخلية بحيث يمكنك مقارنة ذلك في الحلقة الخارجية لا تجعل من الأسهل فهم رمز IMHO.

ومن كافة الاقتراحات المذكورة أعلاه أود أن تجنب استخدام آلية حاول / catch لأن الاستثناءات يجب أن تكون محفوظة لظروف استثنائية، وليس التحكم في التدفق العادي.

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

bool exit_loops = false;
for (int a = 0; a < A && !exit_loops; ++a)
{
    for (int b = 0; b < B && !exit_loops; ++b)
    {
        if (some_condition) exit_loops = true;
    }
}

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

وأخيرا لا تخافوا من استخدام غوتو في هذا الظرف، وعادة في غوتو سيئة البرمجة غير منظم، ولكن في بعض الحالات (مثل هذا) فهي مفيدة جدا.

bool done = false;

for (int i = 0; i < maxi && !done; ++i)
    for (int j = 0; j < maxj && !done; ++j)
        if (i == 4 && i < maxi && j == 3 && j < maxj )
             done = true;
        else {
        }

وأو هل يمكن أن مجرد غوتو. أم لا: -)

وأنت لا يمكن القفز مثل هذا في C / C ++:

for (...)
{
  for (...)
  {
    // from here...
  }
}
// ...to here

ودون استخدام غوتو. كنت في حاجة الى بناء مثل:

for (...)
{
  bool
    exit = false;

  for (...)
  {
    if (do_exit)
    {
      exit = true; // or set outer loop counter to end value
      break;
    }
  }
  if (exit)
  {
    break;
  }
}

وبدلا من ذلك، استخدام رمي والصيد - ولكن هذا ليس كبيرا منذ رمي يجب حقا أن تستخدم للحصول على استثناءات وليس التحكم في التدفق

وهناك طريقة نظيفة هي لجعل الحلقة الداخلية وظيفة:

bool F ()
{
  if inner loop terminates, return false else return true
}

void G ()
{
  for (...)
  {
    if (!F ())
    {
      break;
    }
  }
}
for (int i = 0; i < maxi; ++i)
{
    int j = 0;
    for (j = 0; j < maxj; ++j)
    {
         if (i == 4 && j == 3) // i < maxi and j < maxj otherwise we would not be here
             break; // exit inner loop
    }
    if (i == 4 && j == 3) // i < maxi and j < maxj otherwise we would not be here
        break; // exit outer loop
}

هل يمكن استخدام غوتو بيان ، ولكن هذا يعتبر عموما ممارسة سيئة.

والخيار الآخر الخاص بك هو أن تفعل شيئا من هذا القبيل

int i;
int j = 0;
for (i = 0; i < maxi && !(i==4 && j==3); ++i)
    for (j = 0; j < maxj && !(i==4 && j==3); ++j)

قراءة رمز لا ينبغي أن يكون مثل القراءة محقق كتاب(التي تحتاج دائما إلى أحسب)...

على سبيل المثال:

جافا:

iterate_rows:
for (int i = 0; i < maxi; ++i)
{       
    for (int j = 0; j < maxj; ++j)
    {
        if (i == 4 < maxi && j == 3 < maxj) 
            break iterate_rows;
        else
            continue iterate_rows;
    }   
}

أنت لا تحتاج إلى معرفة لأي كسر iterate_rows هل أنت مجرد قراءتها.

C++:

//iterate_rows:
for (int i = 0; i < maxi; ++i)
{
    for (int j = 0; j < maxj; ++j)
    {
        if (i == 4 < maxi && j == 3 < maxj) 
            goto break_iterate_rows;
        else
            goto continue_iterate_rows;
    }

continue_iterate_rows:;
}
break_iterate_rows:;

غوتو break_iterate_rows هو مجرد مرئية نسخة من كسر iterate_rows

إذا كنت تحصر استخدام goto و التسميات على هذا النوع من التعليمات البرمجية فقط ، فلن تكون معرفة القصد.الحد من استخدام goto و التسميات على هذا النوع من التعليمات البرمجية سوف تجعلك مجرد قراءة رمز, لا تحليل أو الاعتقاد بها.سوف لا يكون متهما شر مبرمج.

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

P. S.

زوج تلك التسميات مع تعليقات(قبل حلقة) ، بحلول الوقت الذي تقرأ الماضي تلك الخطوط مع غوتو بيان تعلمون القصد من تلك gotos

لدي بعض الاقتراحات:

  1. رمي....وضع اثنين من الحلقات داخل "محاولة {}" ثم "الصيد" "رمي" على شرط.

  2. وضع اثنين من الحلقات في طريقة العائد على الشرط.

  3. غوتو ليس الشر لها استخدام وضع الناس ذلك أيضا....يمكنك استخدام "غوتو" يمكن أن يكون أوضح رمز ، خاصة عند التعامل مع الأخطاء.أنا لم تستخدم واحدة في 20 عاما.

توني

ولقد حاولت دائما إلى الابتعاد عن التصريحات goto (كان ينظر دائما إلى أسفل على في المدرسة وعملي لسبب ما). وأود أن استخدام شيء مثل ما اقترح Daemin.

ويمكنك استخدام تسميات، شيء على غرار:

Outer:
for(...)
{
    Inner:
    for(...)
    {
    if(condition)
        {
        goto End;
        }
    }
}
End:

في جاوة يمكنك تمرير تسميات لكسر أعتقد؟

وتحرير - تغيير في غوتو لإنهاء بدلا من الخارجي، ولكن أنا لا أعتقد أن مندوب سلبي له ما يبرره. هذه الإجابة يعطي أبسط طريقة للقيام بذلك.

وهناك سبب آخر لإعادة النظر في بناء for هو تماما أن الاستطلاعية التي يمنع الوصول إلى المتغيرات التي تسيطر عليها بعد إنهاء الحلقة. قيمة (ق) للمتغير (ق) التي تحور في حلقة يجوز مفيدة لمجموعة متنوعة من الأسباب (على سبيل المثال لتمييز النجاح من الفشل في البحث) التي من شأنها أن تتطلب خلاف ذلك متغيرات إضافية للحفاظ على تلك المعلومات بعد خروج النطاق. وهنا مثال صغير الذي يبحث مجموعة مربع اسمه a بقيمة target (على افتراض أن SIZE وغير صفرية، وإلا أي بحث ضروري!):

int i = 0;
int j = 0;
while (i < SIZE && a[i][j] != target) { // still in array but not at target
    if (SIZE <= ++j) {                  // fallen off the end of a row
        j = 0;
        ++i;
    }
}

ورمز لاحقة يمكن استخدام i < SIZE لتحديد ما إذا كانت تقع القيمة المطلوبة.

وهناك ميزة أخرى ما سبق هو المرونة. لنفترض أننا الآن علما بأن القيم في صفوف a وتصاعدي، وبالتالي فإن ما تبقى من صف غير ذي صلة إذا تم مصادفة قيمة أكبر من target. فإنه من السهل أن تعرف بالضبط ما تغيير لجعل، وحيث لتحقيق ذلك. لأن هذه المعلومات الجديدة تسمح لنا للتخلي عن الصف الحالي، إلا يتأثر القرار الداخلي، ليصبح:

    if (target < a[i][j] || SIZE <= ++j) { // can't be in row or fallen off end
    ...

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

أفضل طريقة رأيت يتضمن وحدات الماكرو وgotos، ولكنها في الواقع تماما لطيفة (وصلة للنشر يبدأ بالحديث عن بيرل، ولكن الفقرة الأخيرة أو نحو ذلك يقدم وحدات الماكرو).

وانها تسمح لك لكتابة التعليمات البرمجية مثل:

named (LOOPS) for (i=1; i<10; i++) {
    for (j=1; j<10; j++) {
        for (j=1; j<10; j++) {
            /* Process data[i][j][k] here */
            if (data[i][j][k] < threshold) break(LOOPS);
        }
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top