วิธีสิ้นสุดรหัส C ++


267

ฉันต้องการให้รหัส C ++ หยุดทำงานหากตรงตามเงื่อนไขบางประการ แต่ฉันไม่แน่ใจว่าจะทำอย่างไร ดังนั้น ณ จุดใดถ้าifคำสั่งเป็นจริงยุติโค้ดเช่นนี้:

if (x==1)
{
    kill code;
}

98
ใช้ตรรกะที่เหมาะสม ในการmain()ใช้งานคืนในฟังก์ชั่นใช้ค่าตอบแทนที่เหมาะสมหรือโยนข้อยกเว้นที่เหมาะสม ห้ามใช้exit()!
kay - SE เลว

6
@JonathanLeffler: เมื่อคอมไพล์ด้วยการNDEBUGกำหนดassertอาจจะกลายเป็นไม่ op ดังนั้นคุณไม่ควรพึ่งพามันมากกว่า detecing บั๊ก
MvG

13
@jamesqf กreturnจากmain()เป็นตรรกะที่ดีเลิศ มันตั้งรหัสทางออกที่รายงานโดยโปรแกรมไปยังระบบปฏิบัติการซึ่งจะมีประโยชน์ในหลายกรณี (ถ้าโปรแกรมของคุณสามารถใช้เป็นส่วนหนึ่งของกระบวนการที่มีขนาดใหญ่ตัวอย่าง)
AAT

11
ที่น่าสนใจคำถามนี้ซ้ำซ้อนกับคำถามนี้เมื่อ 5 ปีที่แล้วซึ่งคำตอบที่ยอมรับแตกต่างกันมาก: stackoverflow.com/questions/1116493/how-to-quit-ac-programฉันเดาว่ามันใช้ชุมชน 5 ปีเพื่อเรียนรู้ว่าสุ่มสี่สุ่มห้า โทร std :: exit อาจไม่ดีหรือ
Brandin

5
คำถามทำไมการใช้งานexit()ถึงถือว่าไม่ดี - SO 25141737และวิธีการออกจากโปรแกรม C ++ - SO 1116493ตอนนี้ปิดเหมือนกันกับอันนี้ คนแรกของคนเหล่านั้นมีการอ้างอิงถึง 'ซอฟต์แวร์แบบ Crash-only' ที่อาจคุ้มค่ากับการดูถ้าเพียงเพื่อกระตุ้นความคิดของคุณเกี่ยวกับวิธีการเขียนซอฟต์แวร์ที่มีประสิทธิภาพ
Jonathan Leffler

คำตอบ:


431

มีหลายวิธี แต่แรกที่คุณต้องเข้าใจว่าทำไมการล้างวัตถุเป็นสิ่งสำคัญและด้วยเหตุนี้เหตุผลที่std::exitเป็นชายขอบในหมู่โปรแกรมเมอร์ C ++

ไร่และคลี่คลายคลี่คลาย

C ++ ใช้ประโยชน์จากสำนวนที่เรียกว่าRAIIซึ่งในแง่ง่ายๆหมายความว่าวัตถุควรทำการเริ่มต้นในตัวสร้างและการล้างข้อมูลใน destructor ตัวอย่างเช่นstd::ofstreamคลาส [อาจ] เปิดไฟล์ในระหว่างตัวสร้างจากนั้นผู้ใช้ทำการดำเนินการกับมันและในที่สุดในตอนท้ายของวงจรชีวิตของมันมักจะถูกกำหนดโดยขอบเขตของมัน destructor ที่เรียกว่าปิดไฟล์และวูบวาบ เนื้อหาที่เป็นลายลักษณ์อักษรใด ๆ ลงในดิสก์

จะเกิดอะไรขึ้นถ้าคุณไม่ไปที่ destructor เพื่อล้างข้อมูลและปิดไฟล์ ใครจะรู้! แต่อาจจะไม่เขียนข้อมูลทั้งหมดที่ควรจะเขียนลงในไฟล์

เช่นพิจารณารหัสนี้

#include <fstream>
#include <exception>
#include <memory>

void inner_mad()
{
    throw std::exception();
}

void mad()
{
    auto ptr = std::make_unique<int>();
    inner_mad();
}

int main()
{
    std::ofstream os("file.txt");
    os << "Content!!!";

    int possibility = /* either 1, 2, 3 or 4 */;

    if(possibility == 1)
        return 0;
    else if(possibility == 2)
        throw std::exception();
    else if(possibility == 3)
        mad();
    else if(possibility == 4)
        exit(0);
}

เกิดอะไรขึ้นในแต่ละความเป็นไปได้คือ:

  • ความเป็นไปได้ที่ 1: การส่งคืนจะออกจากขอบเขตของฟังก์ชันปัจจุบันดังนั้นจึงทราบเกี่ยวกับจุดสิ้นสุดของวงจรชีวิตของการosเรียกใช้ destructor และทำการล้างข้อมูลที่เหมาะสมโดยการปิดและล้างแฟ้มไปยังดิสก์
  • ความเป็นไปได้ที่ 2: การโยนข้อยกเว้นยังช่วยดูแลวงจรชีวิตของวัตถุในขอบเขตปัจจุบันด้วยดังนั้นการทำความสะอาดที่เหมาะสม ...
  • ความเป็นไปได้ที่ 3: ที่นี่สแต็คคลี่คลายเข้าสู่การกระทำ! แม้ว่าข้อยกเว้นจะถูกโยนทิ้งที่inner_mad, unwinder จะไปแม้ว่าสแต็คของmadและmainจะดำเนินการล้างที่เหมาะสมวัตถุทั้งหมดจะได้รับการ destructed อย่างถูกต้องรวมทั้งและptros
  • ความเป็นไปได้ที่ 4:นี่ไง exitเป็นฟังก์ชั่น C และไม่ทราบหรือไม่เข้ากันกับสำนวน C ++ มันไม่ได้ทำการล้างข้อมูลบนวัตถุของคุณรวมถึงosในขอบเขตเดียวกัน ดังนั้นไฟล์ของคุณจะไม่ถูกปิดอย่างถูกต้องและด้วยเหตุนี้เนื้อหาจึงอาจไม่ถูกเขียนลงไป!
  • ความเป็นไปได้อื่น ๆ :มันจะออกจากขอบเขตหลักโดยการดำเนินการโดยปริยายreturn 0และทำให้มีผลเช่นเดียวกับความเป็นไปได้ 1 เช่นการล้างที่เหมาะสม

แต่ไม่แน่ใจเกี่ยวกับสิ่งที่ฉันเพิ่งบอกคุณ (ส่วนใหญ่เป็นไปได้ที่ 2 และ 3); อ่านต่อและเราจะค้นหาวิธีดำเนินการล้างข้อมูลตามข้อยกเว้นที่เหมาะสม

วิธีที่เป็นไปได้เพื่อยุติ

กลับจากหลัก!

คุณควรทำเช่นนี้ทุกครั้งที่ทำได้ ต้องการกลับจากโปรแกรมของคุณเสมอโดยส่งคืนสถานะทางออกที่เหมาะสมจากหลัก

ผู้เรียกโปรแกรมของคุณและอาจเป็นระบบปฏิบัติการอาจต้องการทราบว่าสิ่งที่โปรแกรมของคุณควรทำเสร็จเรียบร้อยหรือไม่ ด้วยเหตุผลเดียวกันนี้คุณควรส่งคืนค่าศูนย์หรือEXIT_SUCCESSเพื่อส่งสัญญาณว่าโปรแกรมสิ้นสุดลงอย่างสมบูรณ์และEXIT_FAILUREเพื่อส่งสัญญาณว่าโปรแกรมหยุดทำงานไม่สำเร็จรูปแบบอื่น ๆ ของค่าตอบแทนจะถูกกำหนดโดยการนำไปใช้ ( §18.5 / 8 )

อย่างไรก็ตามคุณอาจจะลึกมากในสแต็คการโทรและการคืนทั้งหมดอาจเจ็บปวด ...

[อย่า] โยนข้อยกเว้น

การโยนข้อยกเว้นจะทำการล้างวัตถุที่เหมาะสมโดยใช้การคลี่คลายคลี่คลายโดยการเรียก destructor ของทุกวัตถุในขอบเขตก่อนหน้าใด ๆ

แต่นี่คือการจับ ! มันถูกกำหนดให้มีการนำไปใช้งานไม่ว่าจะทำการคลี่คลายสแต็กหรือไม่เมื่อข้อยกเว้นที่ส่งออกมานั้นไม่ได้รับการจัดการ(โดยประโยค catch (... ))หรือแม้ว่าคุณจะมีnoexceptฟังก์ชั่นอยู่ตรงกลางของ call stack นี่คือที่ระบุไว้ใน§15.5.1 [ยกเว้น.terminate] :

  1. ในบางสถานการณ์การจัดการข้อยกเว้นต้องถูกทอดทิ้งสำหรับเทคนิคการจัดการข้อผิดพลาดที่ละเอียดน้อยกว่า [หมายเหตุ: สถานการณ์เหล่านี้คือ:

    [ ... ]

    - เมื่อกลไกการจัดการข้อยกเว้นไม่สามารถหาตัวจัดการสำหรับข้อยกเว้นโยน (15.3) หรือเมื่อการค้นหาตัวจัดการ (15.3) พบบล็อกด้านนอกสุดของฟังก์ชั่นที่มีnoexcept-specificationที่ไม่อนุญาตข้อยกเว้น (15.4) หรือ [ ... ]

    [ ... ]

  2. ในกรณีเช่นนี้ std :: terminate () ถูกเรียก (18.8.3) ในสถานการณ์ที่ไม่พบตัวจัดการที่ตรงกันจะมีการกำหนดการนำไปใช้หรือไม่สแต็กไม่ถูกคลายออกก่อนที่ std :: terminate () จะถูกเรียกว่า [... ]

ดังนั้นเราต้องจับมัน!

อย่าโยนข้อยกเว้นและจับมันเป็นหลัก!

เนื่องจากข้อยกเว้นที่ไม่ถูกตรวจจับอาจไม่ทำการคลายสแต็ก(และดังนั้นจะไม่ทำการล้างข้อมูลที่เหมาะสม)เราควรตรวจจับข้อยกเว้นในหลักแล้วจึงกลับสถานะการออก ( EXIT_SUCCESSหรือEXIT_FAILURE)

ดังนั้นการตั้งค่าที่ดีน่าจะเป็น:

int main()
{
    /* ... */
    try
    {
        // Insert code that will return by throwing a exception.
    }
    catch(const std::exception&)  // Consider using a custom exception type for intentional
    {                             // throws. A good idea might be a `return_exception`.
        return EXIT_FAILURE;
    }
    /* ... */
}

[อย่า] std :: exit

สิ่งนี้ไม่ทำการคลี่คลายการเรียงลำดับใด ๆ และไม่มีวัตถุใดที่มีชีวิตบนสแต็กจะเรียก destructor ที่เกี่ยวข้องเพื่อทำการล้างข้อมูล

สิ่งนี้ถูกบังคับใช้ใน§3.6.1 / 4 [basic.start.init] :

ยกเลิกโปรแกรมโดยไม่ออกจากบล็อกปัจจุบัน (เช่นโดยการเรียกฟังก์ชั่นมาตรฐาน :: ออก (int) (18.5)) ไม่ทำลายวัตถุใด ๆ ที่มีระยะเวลาการจัดเก็บข้อมูลอัตโนมัติ (12.4) ถ้า std :: exit ถูกเรียกให้จบโปรแกรมในระหว่างการทำลายวัตถุที่มีระยะเวลาคงที่หรือการจัดเก็บด้ายโปรแกรมมีพฤติกรรมที่ไม่ได้กำหนด

ลองคิดดูสิทำไมคุณจะทำสิ่งนี้ คุณมีวัตถุกี่ชิ้นที่ได้รับความเสียหายอย่างเจ็บปวด?

ทางเลือกอื่น [ไม่ดี]

มีวิธีอื่นในการยกเลิกโปรแกรม(นอกเหนือจากการหยุดทำงาน)แต่ไม่แนะนำให้ทำ เพียงเพื่อความกระจ่างพวกเขาจะถูกนำเสนอที่นี่ ขอให้สังเกตว่าการยกเลิกโปรแกรมปกติ ไม่ได้หมายถึงการคลี่คลายสแต็ก แต่เป็นเรื่องปกติสำหรับระบบปฏิบัติการ

  • std::_Exit ทำให้โปรแกรมหยุดทำงานตามปกติและนั่นก็คือ
  • std::quick_exitทำให้การยกเลิกโปรแกรมปกติและstd::at_quick_exitตัวจัดการการโทรไม่มีการดำเนินการล้างข้อมูลอื่น
  • std::exitทำให้โปรแกรมหยุดทำงานปกติแล้วเรียกเครื่องมือstd::atexitจัดการ การล้างข้อมูลประเภทอื่น ๆ จะดำเนินการเช่นการเรียก destructors วัตถุคงที่
  • std::abortทำให้โปรแกรมหยุดทำงานผิดปกติไม่มีการล้างข้อมูล สิ่งนี้ควรถูกเรียกใช้หากโปรแกรมสิ้นสุดลงด้วยวิธีที่ไม่คาดคิดจริงๆ มันจะไม่ทำอะไรเลยนอกจากส่งสัญญาณระบบปฏิบัติการเกี่ยวกับการเลิกจ้างที่ผิดปกติ บางระบบดำเนินการถ่ายโอนข้อมูลหลักในกรณีนี้
  • std::terminateโทรstd::terminate_handlerที่โทรstd::abortตามค่าเริ่มต้น

25
นี่เป็นข้อมูลที่ค่อนข้างชัดเจน: ฉันไม่เคยรู้เลยว่าการโยนข้อยกเว้นที่ไม่ได้จัดการที่ใดก็ได้ (ตัวอย่างเช่น: บางการnewโยนstd::bad_allocและโปรแกรมของคุณลืมที่จะตรวจจับข้อยกเว้นนั้นทุกที่) จะไม่คลายสแต็กอย่างเหมาะสมก่อนที่จะยุติ นี้ดูเหมือนว่าโง่กับฉัน: ก็จะได้รับเรื่องง่ายที่จะเป็นหลักห่อเรียกร้องให้mainในเล็กน้อยtry{- }catch(...){}บล็อกที่จะให้แน่ใจว่าสแต็คคลี่คลายทำอย่างถูกต้องในกรณีดังกล่าวไม่มีค่าใช้จ่าย (โดยที่ฉันหมายถึง: โปรแกรมไม่ได้ใช้นี้จะไม่มีการจ่าย โทษ) มีเหตุผลพิเศษใด ๆ ที่ไม่ได้ทำ?
Marc van Leeuwen

12
@MarcvanLeeuwen เหตุผลหนึ่งที่เป็นไปได้คือการแก้ไขข้อบกพร่อง: คุณต้องการเจาะเข้าไปในดีบักทันทีที่มีข้อยกเว้นที่ไม่สามารถจัดการได้ การยกเลิกการสแต็กและการล้างข้อมูลบนเครื่องจะลบบริบทของสิ่งที่ทำให้เกิดความผิดพลาดที่คุณต้องการตรวจแก้จุดบกพร่อง หากไม่มีดีบักเกอร์อยู่อาจเป็นการดีกว่าที่จะถ่ายโอนข้อมูลคอร์เพื่อให้สามารถวิเคราะห์การชันสูตรศพได้
Hugh Allen

11
บางครั้งเบราว์เซอร์ของฉันมีข้อผิดพลาด (ฉันตำหนิแฟลช) และใช้ RAM หลายกิกะไบต์และระบบปฏิบัติการของฉันดัมพ์หน้าบนฮาร์ดไดรฟ์ทำให้ทุกอย่างช้าลง เมื่อฉันปิดเบราว์เซอร์จะเป็นการคลายสแต็กที่เหมาะสมหมายความว่า RAM กิกะไบต์เหล่านั้นทั้งหมดจะถูกอ่านจากฮาร์ดไดรฟ์และคัดลอกไปยังหน่วยความจำเพื่อให้วางจำหน่ายซึ่งใช้เวลาประมาณหนึ่งนาที ฉันหวังว่าพวกเขาจะใช้std::abortแทนเพื่อให้ระบบปฏิบัติการสามารถปล่อยหน่วยความจำซ็อกเก็ตและตัวอธิบายไฟล์ทั้งหมดโดยไม่ต้องสลับเป็นเวลาหนึ่งนาที
nwp

2
@nwp ฉันเข้าใจความรู้สึก แต่ฆ่าไฟล์เสียหายพฤษภาคมทันทีไม่บันทึกแท็บล่าสุดของฉัน ฯลฯ :)
พอลผัก

2
@ PaulDraper แน่นอนว่าฉันจะไม่ยอมทนถ้าเบราว์เซอร์ไม่สามารถเรียกคืนแท็บที่ฉันเปิดก่อนที่จะเกิดการสูญเสียพลังงาน แน่นอนถ้าฉันเพิ่งเปิดแท็บและยังไม่มีเวลาบันทึกเลยมันจะหายไป แต่นอกจากนั้นฉันบอกว่าไม่มีข้อแก้ตัวสำหรับการสูญเสียมัน
kasperd

61

ดังที่มาร์ตินยอร์กเอ่ยถึงทางออกไม่จำเป็นต้องทำความสะอาดเหมือนกลับมา

จะดีกว่าเสมอหากใช้ผลตอบแทนในตำแหน่งทางออก ในกรณีที่คุณไม่ได้อยู่ในหลักไม่ว่าคุณต้องการออกจากโปรแกรมใดให้กลับไปที่หน้าหลักก่อน

ลองพิจารณาตัวอย่างด้านล่าง ด้วยโปรแกรมต่อไปนี้ไฟล์จะถูกสร้างขึ้นด้วยเนื้อหาที่กล่าวถึง แต่ถ้าส่งคืนความคิดเห็น & uncommented exit (0) คอมไพเลอร์ไม่รับรองว่าไฟล์จะมีข้อความที่ต้องการ

int main()
{
    ofstream os("out.txt");
    os << "Hello, Can you see me!\n";
    return(0);
    //exit(0);
}

ไม่เพียงแค่นี้การมีจุดออกหลายจุดในโปรแกรมจะทำให้การดีบักยากขึ้น ใช้ exit เท่านั้นเมื่อสามารถพิสูจน์ได้


2
คุณแนะนำอะไรเพื่อให้บรรลุพฤติกรรมนี้ในโปรแกรมที่ใหญ่ขึ้นอีกเล็กน้อย? คุณจะกลับไปยังหน้าหลักได้อย่างหมดจดได้อย่างไรหากอยู่ลึกลงไปในรหัสเงื่อนไขข้อผิดพลาดจะถูกเรียกที่ควรออกจากโปรแกรม?
Janusz

5
@ Janusz ในกรณีนี้คุณสามารถใช้ / throw exception ถ้าไม่คืนค่าที่กำหนดไว้ล่วงหน้าเช่นมีค่า return จากฟังก์ชันเช่น return 0 เมื่อสำเร็จ 1 ในกรณีที่ล้มเหลว แต่ดำเนินการต่อ , -1 ในกรณีที่เกิดข้อผิดพลาด & ออกจากโปรแกรม อิงจากค่าส่งคืนจากฟังก์ชันหากเป็นความล้มเหลวเพียงแค่ส่งคืนจากหลักหลังจากดำเนินการเรียกใช้การล้างข้อมูลเพิ่มเติม ในที่สุดใช้ทางออกอย่างรอบคอบฉันไม่ได้ตั้งใจจะหลีกเลี่ยง
Narendra N

1
@NarendraN "การล้างข้อมูลที่จำเป็น" นั้นคลุมเครือ - ระบบปฏิบัติการจะดูแล (Windows / Linux) ที่หน่วยความจำและการจัดการไฟล์ถูกปล่อยออกมาอย่างถูกต้อง สำหรับเอาต์พุตไฟล์ "หายไป": หากคุณยืนยันว่านี่อาจเป็นปัญหาจริงโปรดดูstackoverflow.com/questions/14105650/how-does-stdflush-work หากคุณมีเงื่อนไขข้อผิดพลาดการบันทึกที่เหมาะสมจะบอกคุณว่าโปรแกรมของคุณ ถึงสถานะที่ไม่ได้กำหนดและคุณสามารถตั้งค่าเบรกพอยต์ได้ก่อนหน้าจุดเข้าสู่ระบบ การแก้จุดบกพร่องนั้นยากขึ้นอย่างไร
Markus

2
โปรดทราบว่าคำตอบนี้ถูกผสานจากคำถามวิธีการออกจากโปรแกรม C ++ - ดังนั้น 1116493 คำตอบนี้เขียนประมาณ 6 ปีก่อนที่จะถามคำถามนี้
Jonathan Leffler

สำหรับ C ++ ที่ทันสมัยใช้ return (EXIT_SUCCESS);แทนreturn(0)
Jonas Stein

39

เรียกใช้std::exitฟังก์ชัน   


2
destructors ของวัตถุใดถูกเรียกเมื่อคุณเรียกใช้ฟังก์ชันนั้น
ร็อบเคนเนดี้

37
exit () ไม่ส่งคืน ดังนั้นจึงไม่มีการคลายสแต็กเกิดขึ้น ไม่ใช่แม้แต่วัตถุระดับโลกก็ไม่ได้ถูกทำลาย แต่ฟังก์ชั่นที่ลงทะเบียนด้วย atexit () จะถูกเรียกใช้
Martin York

16
กรุณาอย่าโทรexit()เมื่อรหัสห้องสมุดของคุณทำงานในกระบวนการโฮสต์ของฉัน - หลังจะออกในกลางไม่มีที่ไหนเลย
sharptooth

5
โปรดทราบว่าคำตอบนี้ถูกผสานจากคำถามวิธีการออกจากโปรแกรม C ++ - ดังนั้น 1116493 คำตอบนี้เขียนประมาณ 6 ปีก่อนที่จะถามคำถามนี้
Jonathan Leffler

23

ผู้คนกำลังพูดว่า "call exit (return code)" แต่นี่เป็นรูปแบบที่ไม่ดี ในโปรแกรมขนาดเล็กมันใช้ได้ แต่มีปัญหาหลายประการ:

  1. คุณจะพบว่ามีหลายจุดออกจากโปรแกรม
  2. มันทำให้รหัสซับซ้อนมากขึ้น (เช่นการใช้ goto)
  3. ไม่สามารถปล่อยหน่วยความจำที่จัดสรรในรันไทม์

จริงๆแล้วครั้งเดียวที่คุณควรจะออกจากปัญหาคือใช้บรรทัดนี้ใน main.cpp:

return 0;

หากคุณใช้ exit () เพื่อจัดการข้อผิดพลาดคุณควรเรียนรู้เกี่ยวกับข้อยกเว้น (และข้อยกเว้นการซ้อน) เป็นวิธีที่สวยงามและปลอดภัยกว่า


9
ในสภาพแวดล้อมแบบมัลติเธรดข้อยกเว้นที่เกิดขึ้นในเธรดอื่นจะไม่ได้รับการจัดการแม้ว่าจะเป็น main () - การสื่อสารข้ามเธรดด้วยตนเองบางอย่างจำเป็นต้องมีก่อนที่เธรดรองจะหมดอายุ
Steve Gilham

3
1. และ 2. ขึ้นอยู่กับโปรแกรมเมอร์โดยการบันทึกที่เหมาะสมนี่ไม่ใช่ปัญหาเนื่องจาก exeuction หยุดตลอดไป สำหรับ 3: นั่นเป็นเพียงความผิดปกติ OS จะเพิ่มหน่วยความจำ - อาจยกเว้นอุปกรณ์ฝังตัว / เรียลไทม์ แต่ถ้าคุณทำเช่นนั้นคุณอาจรู้สิ่งต่าง ๆ ของคุณ
Markus

1
โปรดทราบว่าคำตอบนี้ถูกผสานจากคำถามวิธีการออกจากโปรแกรม C ++ - ดังนั้น 1116493 คำตอบนี้เขียนประมาณ 6 ปีก่อนที่จะถามคำถามนี้
Jonathan Leffler

1
หากเกิดข้อผิดพลาดคุณไม่ควรคืนค่า 0 คุณควรคืนค่า 1 (หรืออาจเป็นค่าอื่น ๆ แต่ 1 เป็นตัวเลือกที่ปลอดภัยเสมอ)
Kef Schecter

14

return 0;ใส่ที่ใดก็ตามที่คุณต้องการภายในint main()และโปรแกรมจะปิดทันที


the-nightman, @ evan-carlake และคนอื่น ๆ ฉันก็จะเพิ่มเติมว่าคำถาม SO # # 36707นี้ให้การอภิปรายว่าคำสั่งคืนควรจะเกิดขึ้นที่ใดก็ได้ในชีวิตประจำวันหรือไม่ นี่คือทางออก อย่างไรก็ตามขึ้นอยู่กับสถานการณ์ที่เฉพาะเจาะจงฉันจะไม่พูดว่านี่เป็นทางออกที่ดีที่สุด
localhost

1
OP mainกล่าวว่าไม่มีอะไรเกี่ยวกับเรื่องนี้ดังนั้นฉันคิดว่ามันค่อนข้างผื่นจะถือว่ารหัสหมายถึงการเป็นฟังก์ชั่นภายใน
Marc van Leeuwen

@localhost ข้อความสั่ง return เป็นทางเลือกอย่างสมบูรณ์ในทุกสถานการณ์ภายใต้เงื่อนไขใด ๆ อย่างไรก็ตามint main()มีความแตกต่าง โปรแกรมใช้int main()ในการเริ่มต้นและสิ้นสุด ไม่มีวิธีอื่นที่จะทำ โปรแกรมจะทำงานจนกว่าคุณจะคืนค่าจริงหรือเท็จ เกือบตลอดเวลาที่คุณจะคืนค่า 1 หรือจริงเพื่อระบุว่าโปรแกรมได้ปิดอย่างถูกต้อง (เช่น: อาจใช้เท็จถ้าคุณไม่สามารถเพิ่มหน่วยความจำหรือเหตุผลอะไรก็ตาม) การให้โปรแกรมทำงานเองเสร็จเป็นความคิดที่ไม่ดีเสมอตัวอย่าง:int main() { int x = 2; int foo = x*5; std::cout << "blah"; }
Evan Carslake

@EvanCarslake เข้าใจถ้าคุณสังเกตเห็นความคิดเห็นที่ฉันโพสต์ที่อื่นสำหรับคำถามนี้ฉันคุ้นเคยกับเรื่องนี้เกี่ยวกับint main; อย่างไรก็ตามไม่ใช่ความคิดที่ดีที่จะมีคำสั่ง return หลายรายการในรูทีนหลัก ข้อแม้หนึ่งที่อาจเกิดขึ้นคือการปรับปรุงการอ่านรหัส อย่างไรก็ตามการใช้บางสิ่งบางอย่างเช่นธงบูลีนที่เปลี่ยนสถานะเพื่อป้องกันไม่ให้ส่วนรหัสบางส่วนของรหัสทำงานในสถานะแอปพลิเคชันนั้น โดยส่วนตัวแล้วฉันพบคำสั่งส่งคืนทั่วไปทำให้แอปพลิเคชันส่วนใหญ่สามารถอ่านได้มากขึ้น สุดท้ายคำถามเกี่ยวกับการล้างหน่วยความจำและการปิดวัตถุ I / O อย่างถูกต้องก่อนออก
localhost

2
@EvanCarslake คุณไม่ได้กลับtrueจากmainเพื่อระบุการยกเลิกที่ถูกต้อง คุณต้องคืนค่าศูนย์หรือEXIT_SUCCESS(หรือถ้าคุณต้องการfalseซึ่งจะถูกแปลงเป็นศูนย์โดยปริยาย) เพื่อระบุการเลิกจ้างตามปกติ EXIT_FAILUREเพื่อแสดงให้เห็นความล้มเหลวคุณสามารถกลับ ความหมายของรหัสอื่น ๆ คือการกำหนดการใช้งาน (บนระบบ POSIX หมายถึงรหัสข้อผิดพลาดจริง)
Ruslan

11

โปรแกรมจะยุติการทำงานเมื่อโฟลว์การดำเนินการสิ้นสุดฟังก์ชันหลัก

หากต้องการยกเลิกก่อนหน้านี้คุณสามารถใช้ฟังก์ชัน exit (int status) โดยที่ status คือค่าที่ส่งคืนไปยังทุกอย่างที่เริ่มต้นโปรแกรม 0 โดยปกติหมายถึงสถานะที่ไม่ใช่ข้อผิดพลาด


2
โปรดทราบว่าคำตอบนี้ถูกผสานจากคำถามวิธีการออกจากโปรแกรม C ++ - ดังนั้น 1116493 คำตอบนี้เขียนประมาณ 6 ปีก่อนที่จะถามคำถามนี้
Jonathan Leffler

11

ส่งคืนค่าจากคุณmainหรือใช้exitฟังก์ชัน ทั้งคู่ใช้ int ไม่สำคัญว่าคุณจะส่งคืนค่าใดเว้นแต่ว่าคุณมีกระบวนการภายนอกที่คอยดูค่าที่ส่งคืน


3
โปรดทราบว่าคำตอบนี้ถูกผสานจากคำถามวิธีการออกจากโปรแกรม C ++ - ดังนั้น 1116493 คำตอบนี้เขียนประมาณ 6 ปีก่อนที่จะถามคำถามนี้
Jonathan Leffler

11

หากคุณมีข้อผิดพลาดที่ลึกลงไปในรหัสแล้วโยนข้อยกเว้นหรือตั้งรหัสข้อผิดพลาด เป็นการดีกว่าเสมอที่จะโยนข้อยกเว้นแทนที่จะตั้งรหัสข้อผิดพลาด


2
โปรดทราบว่าคำตอบนี้ถูกผสานจากคำถามวิธีการออกจากโปรแกรม C ++ - ดังนั้น 1116493 คำตอบนี้เขียนประมาณ 6 ปีก่อนที่จะถามคำถามนี้
Jonathan Leffler

9

โดยทั่วไปคุณจะใช้exit()วิธีการที่เหมาะสมกับสถานะทางออก

Zero หมายถึงการประสบความสำเร็จ สถานะที่ไม่เป็นศูนย์ระบุว่ามีปัญหาเกิดขึ้น รหัสทางออกนี้ใช้โดยกระบวนการหลัก (เช่นเชลล์สคริปต์) เพื่อตรวจสอบว่ากระบวนการทำงานสำเร็จหรือไม่


1
การใช้ exit MAY หมายความว่าคุณมีปัญหาด้านการออกแบบ หากโปรแกรม bheaves return 0;อย่างถูกต้องมันก็ควรจะยุติเมื่อหลัก ฉันถือว่าexit()เป็นเช่นassert(false);นั้นและควรใช้เฉพาะในการพัฒนาเพื่อแก้ไขปัญหาที่เกิดขึ้น แต่เนิ่นๆ
CoffeDeveloper

2
โปรดทราบว่าคำตอบนี้ถูกผสานจากคำถามวิธีการออกจากโปรแกรม C ++ - ดังนั้น 1116493 คำตอบนี้เขียนประมาณ 6 ปีก่อนที่จะถามคำถามนี้
Jonathan Leffler

7

นอกเหนือจากการเรียก exit (error_code) - ซึ่งเรียกใช้ตัวจัดการ atexit แต่ไม่ใช่ destructors RAII เป็นต้น - มากขึ้นเรื่อย ๆ ฉันใช้ข้อยกเว้น

ดูเหมือนโปรแกรมหลักของฉันจะมากขึ้นเรื่อย ๆ

int main(int argc, char** argv) 
{
    try {
        exit( secondary_main(argc, argv );
    }
    catch(...) {
        // optionally, print something like "unexpected or unknown exception caught by main"
        exit(1);
    }
}

โดยที่ secondary_main ซึ่งทุกสิ่งที่ถูกวางไว้ในตอนแรก - นั่นคือเปลี่ยนชื่อเดิมเป็น secondary_main และเพิ่ม stub main ไว้ด้านบน นี่เป็นเพียงความดีเพื่อให้มีรหัสไม่มากเกินไประหว่างถาดและตรวจจับในหลัก

ถ้าคุณต้องการจับชนิดข้อยกเว้นอื่น ๆ
ฉันชอบจับประเภทข้อผิดพลาดของสตริงเช่น std :: string หรือ char * และพิมพ์ที่ตัวจัดการ catch ใน main

การใช้ข้อยกเว้นเช่นนี้อย่างน้อยจะทำให้มีตัวเรียกใช้ตัวทำลาย RAII เพื่อให้สามารถล้างข้อมูลได้ ซึ่งน่าพอใจและมีประโยชน์

โดยรวมแล้วการจัดการข้อผิดพลาด C - ออกและสัญญาณ - และการจัดการข้อผิดพลาด C ++ - ลอง / จับ / โยนข้อยกเว้น - เล่นด้วยกันอย่างไม่สอดคล้องกันอย่างดีที่สุด

จากนั้นที่คุณตรวจพบข้อผิดพลาด

throw "error message"

หรือประเภทข้อยกเว้นที่เฉพาะเจาะจงมากขึ้น


โดยวิธีการ: ฉันตระหนักดีว่าการใช้ชนิดข้อมูลเช่นสตริงซึ่งอาจเกี่ยวข้องกับการจัดสรรหน่วยความจำแบบไดนามิกไม่ใช่ความคิดที่ดีในหรือรอบตัวจัดการข้อยกเว้นสำหรับข้อยกเว้นที่อาจเกี่ยวข้องกับหน่วยความจำไม่เพียงพอ ค่าคงที่สตริงแบบ C ไม่มีปัญหา
Krazy Glew

1
ในการเรียกexitโปรแกรมของคุณไม่มีประเด็น ตั้งแต่คุณอยู่ในคุณสามารถเพียงแค่main return exitCode;
Ruslan

-1

หากคำสั่ง if ของคุณอยู่ในลูปคุณสามารถใช้

 break; 

หากคุณต้องการหลีกเลี่ยงรหัสบางอย่างและใช้การวนซ้ำต่อไป:

ยังคง;

หากข้อความ if ของคุณไม่อยู่ในลูปคุณสามารถใช้:

 return 0;

Or 




  exit();

-2

exit()ฟังก์ชั่นDude ... ถูกกำหนดไว้ภายใต้ stdlib.h

ดังนั้นคุณต้องเพิ่มตัวประมวลผลล่วงหน้า

ใส่include stdlib.hในส่วนหัว

จากนั้นใช้exit();ที่ใดก็ได้ที่คุณต้องการ แต่อย่าลืมใส่หมายเลข interger ไว้ในวงเล็บของทางออก

ตัวอย่างเช่น:

exit(0);

-2

หากเงื่อนไขที่ฉันทดสอบเป็นข่าวร้ายจริง ๆ ฉันจะทำสิ่งนี้:

*(int*) NULL= 0;

สิ่งนี้ทำให้ฉันมี coredump ที่ดีจากที่ฉันสามารถตรวจสอบสถานการณ์


4
สิ่งนี้อาจได้รับการปรับให้เหมาะสมเนื่องจากจะทำให้เกิดพฤติกรรมที่ไม่ได้กำหนด ในความเป็นจริงทั้งสาขาของการดำเนินการที่มีคำสั่งดังกล่าวสามารถเช็ดออกโดยคอมไพเลอร์
Ruslan

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.