คำตอบที่น่าสนใจ: แม้ว่าฉันจะเห็นด้วยกับพวกเขาทั้งหมด (จนถึงตอนนี้) แต่ก็มีความหมายแฝงที่เป็นไปได้สำหรับคำถามนี้ซึ่งตอนนี้ถูกมองข้ามไปโดยสิ้นเชิง
หากตัวอย่างง่ายๆด้านบนถูกขยายด้วยการจัดสรรทรัพยากรแล้วเกิดข้อผิดพลาดในการตรวจสอบว่าอาจทำให้ทรัพยากรว่างรูปภาพอาจเปลี่ยนไป
ลองพิจารณาแนวทางที่ไร้เดียงสาของผู้เริ่มต้นอาจใช้:
int func(..some parameters...) {
  res_a a = allocate_resource_a();
  if (!a) {
    return 1;
  }
  res_b b = allocate_resource_b();
  if (!b) {
    free_resource_a(a);
    return 2;
  }
  res_c c = allocate_resource_c();
  if (!c) {
    free_resource_b(b);
    free_resource_a(a);
    return 3;
  }
  do_work();
  free_resource_c(c);
  free_resource_b(b);
  free_resource_a(a);
  return 0;
}
ข้างต้นจะแสดงถึงรูปแบบที่รุนแรงของการกลับมาก่อนเวลาอันควร สังเกตว่าโค้ดมีความซ้ำซากจำเจและไม่สามารถบำรุงรักษาได้อย่างไรเมื่อเวลาผ่านไปเมื่อความซับซ้อนเพิ่มขึ้น คนปัจจุบันอาจใช้การจัดการข้อยกเว้นเพื่อจับสิ่งเหล่านี้
int func(..some parameters...) {
  res_a a;
  res_b b;
  res_c c;
  try {
    a = allocate_resource_a(); # throws ExceptionResA
    b = allocate_resource_b(); # throws ExceptionResB
    c = allocate_resource_c(); # throws ExceptionResC
    do_work();
  }  
  catch (ExceptionBase e) {
    # Could use type of e here to distinguish and
    # use different catch phrases here
    # class ExceptionBase must be base class of ExceptionResA/B/C
    if (c) free_resource_c(c);
    if (b) free_resource_b(b);
    if (a) free_resource_a(a);
    throw e
  }
  return 0;
}
ฟิลิปแนะนำหลังจากดูตัวอย่าง goto ด้านล่างแล้วเพื่อใช้สวิตช์ / เคสแบบไม่ต้องหยุดพักภายในบล็อกจับด้านบน หนึ่งสามารถสลับ (typeof (จ)) และแล้วตกผ่านfree_resourcex()สาย แต่นี้ไม่น่ารำคาญและความต้องการการพิจารณาการออกแบบ และจำไว้ว่าสวิตช์ / เคสที่ไม่มีการหยุดพักนั้นเหมือนกับ goto ที่มีป้ายกำกับเดซี่ด้านล่าง ...
ในฐานะที่เป็นมาร์ค B ชี้ให้เห็นใน C ++ ก็ถือว่าเป็นรูปแบบที่ดีที่จะปฏิบัติตามทรัพยากรได้มาคือการเริ่มต้นหลักการRAIIในระยะสั้น สาระสำคัญของแนวคิดคือการใช้การสร้างอินสแตนซ์อ็อบเจ็กต์เพื่อรับทรัพยากร จากนั้นทรัพยากรจะถูกปลดปล่อยโดยอัตโนมัติทันทีที่วัตถุอยู่นอกขอบเขตและมีการเรียกผู้ทำลายล้าง สำหรับทรัพยากรที่อยู่ระหว่างกันจะต้องได้รับการดูแลเป็นพิเศษเพื่อให้แน่ใจว่าลำดับการจัดสรรที่ถูกต้องและการออกแบบประเภทของออบเจ็กต์ที่มีข้อมูลที่จำเป็นสำหรับผู้ทำลายทั้งหมด
หรือในช่วงก่อนวันยกเว้นอาจทำ:
int func(..some parameters...) {
  res_a a = allocate_resource_a();
  res_b b = allocate_resource_b();
  res_c c = allocate_resource_c();
  if (a && b && c) {   
    do_work();
  }  
  if (c) free_resource_c(c);
  if (b) free_resource_b(b);
  if (a) free_resource_a(a);
  return 0;
}
แต่ตัวอย่างที่ง่ายเกินไปนี้มีข้อบกพร่องหลายประการ: สามารถใช้ได้เฉพาะในกรณีที่ทรัพยากรที่จัดสรรไม่ขึ้นอยู่กับกันและกัน (เช่นไม่สามารถใช้สำหรับการจัดสรรหน่วยความจำจากนั้นเปิดที่จับไฟล์จากนั้นอ่านข้อมูลจากแฮนเดิลลงในหน่วยความจำ ) และไม่ได้ระบุรหัสข้อผิดพลาดที่แยกแยะได้เฉพาะบุคคลเป็นค่าส่งคืน
เพื่อให้โค้ดเร็ว (!) มีขนาดกะทัดรัดและอ่านง่ายและขยายได้Linus Torvalds บังคับใช้รูปแบบที่แตกต่างกันสำหรับโค้ดเคอร์เนลที่เกี่ยวข้องกับทรัพยากรแม้จะใช้goto ที่น่าอับอายในลักษณะที่สมเหตุสมผล :
int func(..some parameters...) {
  res_a a;
  res_b b;
  res_c c;
  a = allocate_resource_a() || goto error_a;
  b = allocate_resource_b() || goto error_b;
  c = allocate_resource_c() || goto error_c;
  do_work();
error_c:
  free_resource_c(c);
error_b:
  free_resource_b(b);
error_a:
  free_resource_a(a);
  return 0;
}
สาระสำคัญของการสนทนาในรายการส่งเมลของเคอร์เนลคือคุณลักษณะภาษาส่วนใหญ่ที่ "ต้องการ" เหนือคำสั่ง goto นั้นเป็น gotos โดยปริยายเช่น if / else ขนาดใหญ่ตัวจัดการข้อยกเว้นคำสั่ง loop / break / continue ฯลฯ และ goto ในตัวอย่างข้างต้นถือว่าโอเคเนื่องจากพวกมันกระโดดได้เพียงระยะทางเล็ก ๆ มีป้ายกำกับที่ชัดเจนและไม่มีรหัสของความยุ่งเหยิงอื่น ๆ เพื่อติดตามเงื่อนไขข้อผิดพลาด คำถามนี้ยังได้รับการกล่าวถึงที่นี่ใน StackOverflow
อย่างไรก็ตามสิ่งที่ขาดหายไปในตัวอย่างสุดท้ายเป็นวิธีที่ดีในการส่งคืนรหัสข้อผิดพลาด ฉันกำลังคิดที่จะเพิ่มresult_code++หลังการfree_resource_x()โทรแต่ละครั้งและส่งคืนรหัสนั้น แต่สิ่งนี้จะชดเชยความเร็วที่เพิ่มขึ้นของรูปแบบการเข้ารหัสข้างต้น และยากที่จะคืนค่า 0 ในกรณีที่สำเร็จ บางทีฉันอาจจะไม่ได้จินตนาการ ;-)
ใช่ฉันคิดว่ามีความแตกต่างอย่างมากในคำถามของการเข้ารหัสผลตอบแทนก่อนกำหนดหรือไม่ แต่ฉันคิดว่ามันชัดเจนเฉพาะในโค้ดที่ซับซ้อนกว่าซึ่งยากกว่าหรือเป็นไปไม่ได้ที่จะปรับโครงสร้างและปรับให้เหมาะสมสำหรับคอมไพเลอร์ ซึ่งโดยปกติจะเป็นกรณีเมื่อการจัดสรรทรัพยากรเข้ามามีบทบาท