ครั้งแรกกับคนอื่น ๆ ได้กล่าวสิ่งที่ไม่ว่าชัดเจนใน C ++ IMHO ส่วนใหญ่เป็นเพราะความต้องการและหมอนรองจะค่อนข้างแตกต่างกันมากขึ้นใน C ++ กว่าภาษาอื่น ๆ ทาย C # และ Java ที่มีปัญหาข้อยกเว้น "ที่คล้ายกัน"
ฉันจะแสดงตัวอย่าง std :: stof:
ผ่านสตริงที่ว่างเปล่าไปยัง std :: stof (จะโยน invalid_argument) ไม่ใช่ข้อผิดพลาดในการเขียนโปรแกรม
สัญญาพื้นฐานที่ฉันเห็นมันของฟังก์ชั่นนี้คือมันพยายามที่จะแปลงมันเป็นข้อโต้แย้งในการลอยและความล้มเหลวในการทำเช่นนั้นจะถูกรายงานโดยข้อยกเว้น ข้อยกเว้นที่เป็นไปได้ทั้งสองอย่างนั้นมาจากlogic_error
แต่ไม่ใช่ในแง่ของความผิดพลาดของโปรแกรมเมอร์ แต่ในแง่ของ "ข้อมูลที่ไม่สามารถถูกแปลงเป็นแบบลอยได้"
ในที่นี้หนึ่งอาจบอกว่าlogic_error
ใช้เพื่อระบุว่าเนื่องจากอินพุต (runtime) นั้นเป็นข้อผิดพลาดเสมอที่พยายามแปลงมัน - แต่มันเป็นหน้าที่ของฟังก์ชั่นในการพิจารณาและบอกคุณ (ผ่านข้อยกเว้น)
หมายเหตุด้านข้าง: ในมุมมองนั้น a runtime_error
สามารถถูกมองว่าเป็นสิ่งที่ให้อินพุตเดียวกันกับฟังก์ชันสามารถประสบความสำเร็จในทางทฤษฎีสำหรับการทำงานที่แตกต่างกัน (เช่นการทำงานของไฟล์การเข้าถึงฐานข้อมูล ฯลฯ )
อีกด้านหมายเหตุ: ห้องสมุด C + + regex เลือกที่จะได้รับมันเป็นข้อผิดพลาดจากruntime_error
แม้ว่าจะมีกรณีที่สามารถจำแนกเช่นเดียวกับที่นี่ (รูปแบบ regex ไม่ถูกต้อง)
นี่แสดงให้เห็นว่า IMHO การจัดกลุ่มlogic_
หรือruntime_
ข้อผิดพลาดนั้นค่อนข้างคลุมเครือใน C ++และไม่ได้ช่วยอะไรมากในกรณีทั่วไป (*) - ถ้าคุณต้องการจัดการข้อผิดพลาดเฉพาะคุณอาจต้องจับตาดูทั้งสอง
(*): นั่นไม่ได้หมายความว่ารหัสชิ้นเดียวไม่ควรสอดคล้องกัน แต่ไม่ว่าคุณจะโยนruntime_
หรือlogic_
หรือcustom_
อะไรก็ตามมันไม่สำคัญเลย
หากต้องการแสดงความคิดเห็นทั้งstof
และbitset
:
ฟังก์ชั่นทั้งสองใช้สตริงเป็นอาร์กิวเมนต์และในทั้งสองกรณีมันคือ:
- ไม่น่าสนใจที่จะตรวจสอบผู้โทรว่าสตริงที่กำหนดนั้นถูกต้องหรือไม่ (เช่นกรณีที่แย่ที่สุดที่คุณต้องทำซ้ำฟังก์ชันตรรกะ; ในกรณีของบิตเซ็ตมันไม่ชัดเจนในทันทีว่าสตริงว่างนั้นถูกต้องหรือไม่
- มันเป็นความรับผิดชอบของฟังก์ชั่นในการ "แจง" สตริงดังนั้นจึงต้องมีการตรวจสอบสตริงดังนั้นจึงเหมาะสมที่จะรายงานข้อผิดพลาด "ใช้" สตริงอย่างสม่ำเสมอ (และในทั้งสองกรณีนี่เป็นข้อยกเว้น) .
กฎที่เกิดขึ้นบ่อยครั้งพร้อมกับข้อยกเว้นคือ "ใช้ข้อยกเว้นเฉพาะในสถานการณ์พิเศษ" เท่านั้น แต่ฟังก์ชั่นห้องสมุดควรจะรู้ได้อย่างไรว่าสถานการณ์ใดเป็นพิเศษ?
คำสั่งนี้มี IMHO รากที่สอง:
ประสิทธิภาพการทำงาน : หากฟังก์ชั่นถูกเรียกใช้ในเส้นทางที่สำคัญและกรณี "พิเศษ" นั้นไม่พิเศษนั่นคือจำนวนการส่งผ่านที่สำคัญจะเกี่ยวข้องกับการโยนข้อยกเว้นดังนั้นการจ่ายเงินทุกครั้งสำหรับข้อยกเว้นที่ไม่คลี่คลาย - ไม่สมเหตุสมผล และอาจช้าเกินไป
ถิ่นที่อยู่ของการจัดการข้อผิดพลาด : ถ้าฟังก์ชั่นถูกเรียกและข้อยกเว้นที่ถูกจับได้ทันทีและประมวลผลแล้วมีจุดเล็ก ๆ ในการขว้างปายกเว้นเช่นจัดการข้อผิดพลาดจะมีมากขึ้นอย่างละเอียดกับกว่ากับcatch
if
ตัวอย่าง:
float readOrDefault;
try {
readOrDefault = stof(...);
} catch(std::exception&) {
// discard execption, just use default value
readOrDefault = 3.14f; // 3.14 is the default value if cannot be read
}
นี่คือที่ที่ฟังก์ชั่นเช่นTryParse
vs. Parse
เข้ามาเล่น: หนึ่งรุ่นสำหรับเมื่อรหัสท้องถิ่นคาดว่าสตริงการแจงจะถูกต้องหนึ่งรุ่นเมื่อรหัสท้องถิ่นสมมติว่ามันเป็นที่คาดหวังจริง(เช่นไม่พิเศษ) ที่การแยกวิเคราะห์จะล้มเหลว
อันที่จริงstof
เป็นเพียงเสื้อคลุม (หมายถึง) strtof
ดังนั้นถ้าคุณไม่ต้องการข้อยกเว้นใช้อันนั้น
ดังนั้นฉันควรตัดสินใจอย่างไรว่าควรใช้ข้อยกเว้นหรือไม่สำหรับฟังก์ชั่นเฉพาะ
IMHO คุณมีสองกรณี:
"ไลบรารี่" เหมือนกับฟังก์ชั่น (นำมาใช้บ่อยในบริบทที่แตกต่างกัน): โดยทั่วไปคุณไม่สามารถตัดสินใจได้ อาจมีทั้งสองเวอร์ชันอาจเป็นรุ่นที่รายงานข้อผิดพลาดและตัวห่อหุ้มที่แปลงข้อผิดพลาดที่ส่งคืนเป็นข้อยกเว้น
ฟังก์ชั่น "แอปพลิเคชัน" (เฉพาะสำหรับหยดของรหัสแอปพลิเคชันอาจถูกนำกลับมาใช้ใหม่บางส่วน แต่ถูก จำกัด ด้วยรูปแบบการจัดการข้อผิดพลาดของแอพ ฯลฯ ): ที่นี่มันมักจะชัดเจน หากการเรียกใช้โค้ดโค๊ดฟังก์ชั่นจัดการกับข้อยกเว้นด้วยวิธีที่มีประโยชน์และมีประโยชน์ให้ใช้ข้อยกเว้นเพื่อรายงานข้อผิดพลาดใด ๆ(แต่ดูด้านล่าง) หากรหัสแอปพลิเคชันอ่านและเขียนได้ง่ายขึ้นสำหรับสไตล์การส่งคืนข้อผิดพลาดโดยทั้งหมดใช้วิธีนั้น
แน่นอนว่าจะมีสถานที่ระหว่าง - เพียงแค่ใช้สิ่งที่ต้องการและจำ YAGNI
สุดท้ายฉันคิดว่าฉันควรกลับไปที่คำสั่ง FAQ
อย่าใช้ Throw เพื่อระบุข้อผิดพลาดในการใช้งานฟังก์ชั่น ใช้ assert หรือกลไกอื่น ๆ เพื่อส่งกระบวนการไปยังดีบักเกอร์หรือเพื่อทำให้กระบวนการขัดข้อง ...
ฉันสมัครรับข้อมูลนี้สำหรับข้อผิดพลาดทั้งหมดที่บ่งชี้อย่างชัดเจนว่ามีบางอย่างเกิดความผิดพลาดอย่างรุนแรงหรือว่ารหัสการโทรอย่างชัดเจนไม่รู้ว่ากำลังทำอะไรอยู่
แต่เมื่อสิ่งนี้เหมาะสมมักเป็นแอพพลิเคชั่นที่มีความเฉพาะเจาะจงสูงดังนั้นโปรดดูเหนือไลบรารีโดเมนกับโดเมนแอปพลิเคชัน
สิ่งนี้ย้อนกลับไปที่คำถามว่าจะตรวจสอบเงื่อนไขการโทรได้หรือไม่ แต่ฉันจะไม่ตอบคำถามนั้นยาวเกินไป :-)