ความแตกต่าง: std :: runtime_error vs std :: exception ()


130

อะไรคือความแตกต่างระหว่างstd::runtime_errorและstd::exception? การใช้งานที่เหมาะสมสำหรับแต่ละคนคืออะไร? ทำไมพวกเขาถึงแตกต่างกันตั้งแต่แรก?

คำตอบ:


154

std::exceptionเป็นคลาสที่มีจุดประสงค์เดียวเพื่อใช้เป็นคลาสพื้นฐานในลำดับชั้นของข้อยกเว้น มันไม่มีประโยชน์อื่นใด กล่าวอีกนัยหนึ่งแนวคิดมันเป็นคลาสนามธรรม (แม้ว่าจะไม่ได้กำหนดให้เป็นคลาสนามธรรมในความหมาย C ++ ของคำศัพท์ก็ตาม)

std::runtime_errorเป็นคลาสที่มีความเชี่ยวชาญมากขึ้นจากมากไปหาน้อยstd::exceptionโดยมีวัตถุประสงค์เพื่อโยนทิ้งในกรณีที่เกิดข้อผิดพลาดรันไทม์ต่างๆ มีวัตถุประสงค์สองประการ มันสามารถนำมาโยนด้วยตัวเองหรือมันสามารถทำหน้าที่เป็นชั้นฐานประเภทมากยิ่งขึ้นเฉพาะต่างๆของข้อยกเว้นข้อผิดพลาด runtime เช่นstd::range_error, std::overflow_errorฯลฯ คุณสามารถกำหนดระดับชั้นยกเว้นของคุณเองลงมาจากstd::runtime_errorเช่นเดียวกับคุณสามารถกำหนดข้อยกเว้นของคุณเอง std::exceptionลงมาจากชั้นเรียน

เช่นเดียวกับstd::runtime_errorไลบรารีมาตรฐานประกอบด้วยstd::logic_errorจากมากไปหาน้อยstd::exceptionเช่นกัน

จุดสำคัญของการมีลำดับชั้นนี้คือเพื่อให้ผู้ใช้มีโอกาสใช้กลไกการจัดการข้อยกเว้น C ++ อย่างเต็มประสิทธิภาพ เนื่องจากอนุประโยค 'catch' สามารถจับข้อยกเว้นของ polymorphic ได้ผู้ใช้จึงสามารถเขียน clauses 'catch' ที่สามารถตรวจจับชนิดข้อยกเว้นจากแผนผังย่อยเฉพาะของลำดับชั้นของข้อยกเว้น ตัวอย่างเช่นcatch (std::runtime_error& e)จะจับข้อยกเว้นทั้งหมดจากstd::runtime_errorทรีย่อยโดยปล่อยให้คนอื่น ๆ ทั้งหมดผ่านไป (และบินต่อไปใน call stack)

PS การออกแบบลำดับชั้นของข้อยกเว้นที่มีประโยชน์ (ซึ่งจะช่วยให้คุณสามารถจับเฉพาะประเภทข้อยกเว้นที่คุณสนใจในแต่ละจุดของรหัสของคุณ) เป็นงานที่ไม่สำคัญ สิ่งที่คุณเห็นในไลบรารี C ++ มาตรฐานเป็นแนวทางหนึ่งที่เป็นไปได้ซึ่งเสนอให้กับคุณโดยผู้เขียนภาษา ดังที่คุณเห็นพวกเขาตัดสินใจที่จะแยกประเภทข้อยกเว้นทั้งหมดออกเป็น "ข้อผิดพลาดรันไทม์" และ "ข้อผิดพลาดทางตรรกะ" และให้คุณดำเนินการต่อจากที่นั่นด้วยประเภทข้อยกเว้นของคุณเอง แน่นอนว่ามีวิธีอื่นในการจัดโครงสร้างลำดับชั้นดังกล่าวซึ่งอาจเหมาะสมกว่าในการออกแบบของคุณ

อัปเดต: Portability Linux เทียบกับ Windows

ดังที่ Loki Astari และ unixman83 ระบุไว้ในคำตอบและความคิดเห็นด้านล่างตัวสร้างของexceptionคลาสจะไม่ใช้ข้อโต้แย้งใด ๆ ตามมาตรฐาน C ++ Microsoft C ++ มีตัวสร้างที่รับอาร์กิวเมนต์ในexceptionคลาส แต่นี่ไม่ใช่มาตรฐาน runtime_errorชั้นมีตัวสร้างการมีปากเสียง ( char*) บนแพลตฟอร์มทั้ง Windows และ Linux runtime_errorที่จะพกพาใช้งานได้ดียิ่งขึ้น

(และโปรดจำไว้ว่าเพียงเพราะข้อกำหนดของโครงการของคุณบอกว่าโค้ดของคุณไม่จำเป็นต้องทำงานบน Linux แต่ก็ไม่ได้หมายความว่าจะไม่ต้องทำงานบน Linux)


1
ขอบคุณ. คำตอบที่ดี แม้ว่าฉันจะสงสัยว่าจำเป็นต้องมีข้อยกเว้นประเภทอื่นหรือไม่ ... แค่คิด
ศิวบุตร

1
หากมีความเป็นไปได้ที่สามารถครอบคลุมข้อยกเว้นได้อีกครั้งข้อยกเว้นประเภทอื่นจะเป็นประโยชน์เนื่องจากเราสามารถใช้กลไกการจัดการข้อยกเว้นเพื่อกำหนดข้อยกเว้นไปยังตัวจัดการที่จะพยายามแก้ไขปัญหา หากไม่มีโอกาสในการฟื้นตัวมากกว่าหนึ่งในข้อยกเว้นมาตรฐานก็ใช้ได้
Martin York

1
เช่นเดียวกับกัน: std::exceptionมีกฎที่ทุกกองกำลังที่คุณจะได้รับจาก แน่นอนว่าทุกstdสิ่งล้วนโยนคลาสที่ได้รับจากสิ่งนั้นมา แต่ไม่มีเหตุผลที่จะโยนstd::exceptionวัตถุที่ได้รับเท่านั้น
rubenvb

1
@rubenvb ฉันไม่รู้เกี่ยวกับเรื่องนี้ แต่ฉันคิดว่ามันจะล้างรหัสสำหรับการบำรุงรักษาในอนาคตหากมีการโยนวัตถุของคลาสที่ได้รับจากข้อยกเว้นเท่านั้น ตัวอย่าง: ฉันต้องการค้นหาว่ามีการใช้ข้อยกเว้นที่กำหนดเองใดบ้างในฐานรหัสของฉันและค้นหาคลาสที่ได้มาจากข้อยกเว้น
this.myself

21

std::exceptionควรพิจารณา (สังเกตการพิจารณา) ฐานนามธรรมของลำดับชั้นข้อยกเว้นมาตรฐาน เนื่องจากไม่มีกลไกในการส่งผ่านข้อความใดข้อความหนึ่ง (ในการทำเช่นนี้คุณต้องได้รับและเชี่ยวชาญwhat()) ไม่มีอะไรที่จะหยุดคุณจากการใช้ std :: ข้อยกเว้นและสำหรับแอปพลิเคชันง่ายๆอาจเป็นสิ่งที่คุณต้องการ

std::runtime_errorในทางกลับกันมีตัวสร้างที่ถูกต้องซึ่งยอมรับสตริงเป็นข้อความ เมื่อwhat()ใดที่เรียกว่า const char pointer จะถูกส่งกลับจุดที่สตริง C ที่มีสตริงเดียวกันกับที่ถูกส่งไปยังตัวสร้าง

try
{
    if (badThingHappened)
    {
         throw std::runtime_error("Something Bad happened here");
    }
}
catch(std::exception const& e)
{
    std::cout << "Exception: " << e.what() << "\n";
} 

1
ขอบคุณสำหรับคำตอบมาร์ติน อย่างไรก็ตามฉันใช้ std :: exception () แบบเดียวกับที่คุณอธิบายไว้ข้างต้น เช่น std :: exception () constructor ยังสามารถใช้ std :: string () หรือ const char *
sivabudh

14
ไม่เป็นไปตามมาตรฐาน. std :: ข้อยกเว้นมีตัวสร้างหนึ่งตัวที่ไม่มีข้อโต้แย้ง การใช้เวอร์ชันที่ยอมรับ std :: string หรือ C-String นั้นไม่สามารถพกพาได้
Martin York

10
std::exception(std::string)เพราะไมโครซอฟท์ที่ผมได้นำมาใช้เพื่อการขว้างปา ตอนนี้ฉันรู้แล้วว่าฉันต้องโยนstd::runtime_errorถ้าฉันต้องการให้โค้ดของฉันทำงานใน Linux (GCC)
unixman83
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.