ฉันจะสร้างและบังคับใช้สัญญาเพื่อการยกเว้นได้อย่างไร


33

ฉันพยายามโน้มน้าวให้ทีมของฉันอนุญาตให้ใช้ข้อยกเว้นใน C ++ แทนการส่งคืนบูลisSuccessfulหรือ enum ด้วยรหัสข้อผิดพลาด อย่างไรก็ตามฉันไม่สามารถตอบโต้คำวิจารณ์ของเขาได้

พิจารณาห้องสมุดนี้:

class OpenFileException() : public std::runtime_error {
}

void B();
void C();

/** Does blah and blah. */
void B() {
    // The developer of B() either forgot to handle C()'s exception or
    // chooses not to handle it and let it go up the stack.
    C();
};

/** Does blah blah.
 *
 * @raise OpenFileException When we failed to open the file. */
void C() {
    throw new OpenFileException();
};
  1. พิจารณานักพัฒนาที่เรียกใช้B()ฟังก์ชัน เขาตรวจสอบเอกสารและเห็นว่าไม่มีข้อยกเว้นดังนั้นเขาจึงไม่พยายามตรวจจับอะไรเลย รหัสนี้อาจผิดพลาดของโปรแกรมในการผลิต

  2. พิจารณานักพัฒนาที่เรียกใช้C()ฟังก์ชัน เขาไม่ตรวจสอบเอกสารดังนั้นจึงไม่ตรวจพบข้อยกเว้นใด ๆ การโทรไม่ปลอดภัยและอาจทำให้โปรแกรมหยุดทำงาน

แต่ถ้าเราตรวจสอบข้อผิดพลาดด้วยวิธีนี้:

void old_C(myenum &return_code);

ผู้พัฒนาที่ใช้ฟังก์ชั่นนั้นจะได้รับคำเตือนจากคอมไพเลอร์หากเขาไม่ได้ระบุเหตุผลนั้นและเขาจะพูดว่า "อ๊ะนี่จะส่งคืนรหัสข้อผิดพลาดที่ฉันต้องตรวจสอบ"

ฉันจะใช้ข้อยกเว้นได้อย่างปลอดภัยเพื่อให้มีสัญญาบางประเภทได้อย่างไร


4
@Sjoerd ข้อได้เปรียบหลักคือผู้พัฒนาถูกบังคับโดยคอมไพเลอร์เพื่อให้ตัวแปรกับฟังก์ชั่นในการจัดเก็บรหัสส่งคืน; เขาทราบว่าอาจมีข้อผิดพลาดและเขาควรจัดการกับมัน ดีกว่าไม่มีข้อยกเว้นซึ่งไม่มีการตรวจสอบเวลารวบรวมเลย
DBedrenko

4
"เขาควรจัดการกับมัน" - ไม่มีการตรวจสอบว่าสิ่งนี้เกิดขึ้นเช่นกัน
Sjoerd

4
@Sererd มันไม่จำเป็น เป็นการดีพอที่จะทำให้นักพัฒนาซอฟต์แวร์ทราบว่ามีข้อผิดพลาดเกิดขึ้นและควรตรวจสอบ มันอยู่ในสายตาธรรมดาของผู้ตรวจสอบเช่นกันว่าพวกเขาตรวจสอบข้อผิดพลาดหรือไม่
DBedrenko

5
คุณอาจมีโอกาสที่ดีกว่าในการใช้Either/ Resultmonad เพื่อส่งคืนข้อผิดพลาดในรูปแบบที่ปลอดภัยสำหรับการจัดพิมพ์
Daenyth

5
@gardenhead เนื่องจากนักพัฒนาจำนวนมากไม่ได้ใช้อย่างถูกต้องจบลงด้วยรหัสที่น่าเกลียดและดำเนินการต่อเพื่อตำหนิคุณลักษณะแทนตัวเอง คุณลักษณะข้อยกเว้นที่ถูกตรวจสอบใน Java เป็นสิ่งที่สวยงาม แต่ได้รับการแร็พที่ไม่ดีเพราะบางคนไม่ได้รับมัน
AxiomaticNexus

คำตอบ:


47

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

ข้อยกเว้นมีข้อเสีย; คุณต้องทำคดีตามต้นทุน - ผลประโยชน์
ฉันพบว่าบทความทั้งสองนี้มีประโยชน์: ความจำเป็นของข้อยกเว้นและทุกอย่างผิดปกติด้วยข้อยกเว้น นอกจากนี้ยังโพสต์บล็อกนี้มีความเห็นของผู้เชี่ยวชาญหลายคนในข้อยกเว้นให้ความสำคัญกับ C ในขณะที่ความคิดเห็นของผู้เชี่ยวชาญดูเหมือนจะพึ่งพาได้ดีกับข้อยกเว้น แต่ก็ยังห่างไกลจากฉันทามติที่ชัดเจน

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

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

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

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


1
ขอบคุณสำหรับคำแนะนำและลิงค์ นี่เป็นโครงการใหม่ไม่ใช่โครงการเก่า ฉันสงสัยว่าทำไมข้อยกเว้นจึงแพร่หลายเมื่อพวกเขามีข้อเสียเปรียบครั้งใหญ่ที่ทำให้การใช้งานไม่ปลอดภัย หากคุณตรวจพบข้อยกเว้นระดับ n ที่สูงกว่าจากนั้นคุณปรับเปลี่ยนรหัสและย้ายไปรอบ ๆ ไม่มีการตรวจสอบแบบคงที่เพื่อรับประกันว่าข้อยกเว้นนั้นยังคงถูกจับและจัดการอยู่ (และมากเกินไปที่จะขอให้ผู้ตรวจสอบตรวจสอบฟังก์ชันทั้งหมด )
DBedrenko

3
@Dee เห็นลิงก์ข้างต้นสำหรับข้อโต้แย้งบางอย่างในความโปรดปรานของข้อยกเว้น (ฉันได้เพิ่มลิงก์เพิ่มเติมที่มีความคิดเห็นของผู้เชี่ยวชาญมากขึ้น)

6
คำตอบนี้เป็นจุดที่!
Doc Brown

1
ฉันสามารถระบุจากประสบการณ์ที่พยายามเพิ่มข้อยกเว้นใน codebase ที่มีอยู่ก่อนเป็นความคิดที่ดีจริงๆ ฉันทำงานกับ codebase แล้วและมันก็ยากจริงๆที่จะทำงานด้วยเพราะคุณไม่เคยรู้เลยว่าเกิดอะไรขึ้นในหน้าของคุณ ควรใช้ข้อยกเว้นในโครงการที่คุณวางแผนไว้ล่วงหน้าเท่านั้น
Michael Kohne

26

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


ข้อยกเว้นมีไว้เพื่อไม่ให้จับได้ทั่วทุกที่

ตราบใดที่มีตัวจัดการข้อยกเว้นทั่วไปในลูปหลัก - ขึ้นอยู่กับประเภทของแอปพลิเคชัน (เว็บเซิร์ฟเวอร์บริการในท้องถิ่นยูทิลิตีบรรทัดคำสั่ง ... ) - คุณมักจะมีตัวจัดการข้อยกเว้นทั้งหมดที่คุณต้องการ

ในรหัสของฉันมีเพียงไม่กี่คำสั่ง catch - ถ้ามีเลย - นอกวงหลัก และดูเหมือนว่าจะเป็นวิธีการทั่วไปใน C ++ ที่ทันสมัย


ข้อยกเว้นและรหัสส่งคืนไม่สามารถแยกกันได้

คุณไม่ควรทำสิ่งนี้เป็นวิธีการทั้งหมดหรือไม่ทำอะไรเลย ควรใช้ข้อยกเว้นสำหรับสถานการณ์พิเศษ สิ่งต่างๆเช่น "ไม่พบไฟล์กำหนดค่า" "ดิสก์เต็ม" หรืออย่างอื่นที่ไม่สามารถจัดการได้ในเครื่อง

ความล้มเหลวทั่วไปเช่นการตรวจสอบว่าชื่อไฟล์ที่ผู้ใช้ให้ถูกต้องหรือไม่นั้นไม่ใช่กรณีการใช้งานเพื่อการยกเว้น ใช้ค่าส่งคืนในกรณีเหล่านั้นแทน

ดังที่คุณเห็นจากตัวอย่างข้างต้น "ไม่พบไฟล์" อาจเป็นข้อยกเว้นหรือรหัสส่งคืนทั้งนี้ขึ้นอยู่กับกรณีการใช้งาน: "เป็นส่วนหนึ่งของการติดตั้ง" กับ "ผู้ใช้สามารถพิมพ์ผิด"

ดังนั้นจึงไม่มีกฎเด็ดขาด แนวทางคร่าวๆคือ: หากสามารถจัดการในพื้นที่ให้เป็นค่าส่งคืน; หากคุณไม่สามารถจัดการกับมันแบบโลคัลให้โยนข้อยกเว้น


การตรวจสอบข้อยกเว้นแบบคงที่ไม่มีประโยชน์

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

Java มีการตรวจสอบแบบสแตติก แต่โดยทั่วไปถือว่าเป็นการทดสอบที่ล้มเหลวและภาษาส่วนใหญ่ตั้งแต่ - โดยเฉพาะอย่างยิ่ง C # - ไม่มีการตรวจสอบแบบคงที่ประเภทนั้น นี่เป็นการอ่านที่ดีเกี่ยวกับสาเหตุที่ C # ไม่มีมัน

ด้วยเหตุผลดังต่อ, C ++ ได้เลิกใช้มันในความโปรดปรานของthrow(exceptionA, exceptionB) noexcept(true)ค่าเริ่มต้นคือฟังก์ชั่นสามารถโยนดังนั้นโปรแกรมเมอร์ควรคาดหวังว่าเว้นแต่เอกสารประกอบสัญญาอย่างชัดเจน


การเขียนโค้ดที่ปลอดภัยยกเว้นไม่มีส่วนเกี่ยวข้องกับการเขียนตัวจัดการข้อยกเว้น

ฉันอยากจะบอกว่าการเขียนโค้ดที่ปลอดภัยเป็นข้อยกเว้นทั้งหมดเกี่ยวกับวิธีการหลีกเลี่ยงการเขียนตัวจัดการข้อยกเว้น!

แนวทางปฏิบัติที่ดีที่สุดส่วนใหญ่ตั้งใจจะลดจำนวนตัวจัดการข้อยกเว้น การเขียนโค้ดหนึ่งครั้งและเรียกใช้โดยอัตโนมัติเช่นผ่าน RAII จะทำให้เกิดข้อผิดพลาดน้อยกว่าการคัดลอกโค้ดเดียวกันทั่วทุกที่


3
" ตราบใดที่มีตัวจัดการข้อยกเว้นทั่วไป ... คุณก็โอเคอยู่แล้ว " สิ่งนี้ขัดแย้งกับแหล่งที่มาส่วนใหญ่ซึ่งเน้นว่าเป็นการยากที่จะเขียนข้อยกเว้นที่ปลอดภัย

12
@ dan1111 "การเขียนโค้ดที่ปลอดภัยยกเว้น" มีส่วนเกี่ยวข้องกับการเขียนตัวจัดการข้อยกเว้น การเขียนโค้ดที่ปลอดภัยยกเว้นกำลังใช้ RAII เพื่อแค็ปซูลทรัพยากรโดยใช้ "ทำงานทั้งหมดในเครื่องก่อนจากนั้นใช้ swap / move" และแนวทางปฏิบัติอื่น ๆ ที่ดีที่สุด สิ่งเหล่านี้ท้าทายเมื่อคุณไม่คุ้นเคย แต่ "การเขียนตัวจัดการข้อยกเว้น" ไม่ได้เป็นส่วนหนึ่งของแนวทางปฏิบัติที่ดีที่สุดเหล่านั้น
Sjoerd

4
@AxiomaticNexus ในบางระดับคุณสามารถอธิบายการใช้คุณลักษณะที่ไม่สำเร็จทุกครั้งในฐานะ "ผู้พัฒนาที่ไม่ดี" ความคิดที่ยิ่งใหญ่ที่สุดคือแนวคิดที่ลดการใช้งานที่ไม่ดีเพราะทำให้การทำสิ่งที่ถูกต้องง่ายขึ้น ข้อยกเว้นที่ตรวจสอบแบบคงที่ไม่ได้อยู่ในหมวดหมู่นั้น พวกเขาสร้างงานที่ไม่สมส่วนกับคุณค่าของพวกเขาบ่อยครั้งในสถานที่ที่การเขียนโค้ดไม่จำเป็นต้องสนใจพวกเขา ผู้ใช้ถูกล่อลวงให้ปิดเสียงพวกเขาในวิธีที่ไม่ถูกต้องเพื่อให้คอมไพเลอร์หยุดรบกวนพวกเขา แม้ทำถูกต้องแล้วพวกเขาก็นำไปสู่ความยุ่งเหยิงมากมาย
jpmc26

4
@AxiomaticNexus เหตุผลว่ามันเป็นสัดส่วนคือว่านี้สามารถเผยแพร่สู่เกือบทุกฟังก์ชั่นในฐานรหัสของคุณทั้งหมด เมื่อฟังก์ชั่นทั้งหมดในครึ่งคลาสของฉันเข้าถึงฐานข้อมูลไม่ทุกคนต้องประกาศอย่างชัดเจนว่ามันสามารถโยน SQLException ได้ ไม่มีตัวควบคุมทุกวิธีที่เรียกใช้ เสียงดังกล่าวเป็นค่าลบโดยไม่คำนึงถึงปริมาณงานที่น้อย Sjoerd กระทบเล็บที่หัว: รหัสส่วนใหญ่ไม่จำเป็นต้องเกี่ยวข้องกับข้อยกเว้นเพราะมันไม่สามารถทำอะไรกับพวกเขาได้
jpmc26

3
@AxiomaticNexus ใช่เพราะนักพัฒนาที่ดีที่สุดคือรหัสที่สมบูรณ์แบบพวกเขาจะจัดการกับอินพุตของผู้ใช้ที่เป็นไปได้ทุกครั้งอย่างสมบูรณ์แบบและคุณจะไม่เคยเห็นข้อยกเว้นเหล่านั้นเลย และถ้าคุณทำมันหมายความว่าคุณล้มเหลวในชีวิต อย่างจริงจังอย่าให้ขยะนี้กับฉันเลย ไม่มีใครที่สมบูรณ์แบบแม้กระทั่งสิ่งที่ดีที่สุด และแอปของคุณควรทำงานอย่างมีสติแม้ต้องเผชิญกับข้อผิดพลาดเหล่านั้นแม้ว่า "sanely" จะเป็น "หยุดและส่งหน้าข้อผิดพลาด / ข้อความครึ่งดี" และเดาว่า: นั่นคือสิ่งเดียวกับที่คุณทำกับ 99% ของIOExceptions เช่นกัน การแบ่งส่วนที่ตรวจสอบนั้นเป็นแบบสุ่มและไร้ประโยชน์
jpmc26

8

โปรแกรมเมอร์ C ++ ไม่มองหาข้อกำหนดคุณสมบัติพิเศษ พวกเขามองหาการรับประกันแบบยกเว้น

สมมติว่าชิ้นส่วนของรหัสผิดพลาด โปรแกรมเมอร์สามารถตั้งสมมติฐานอะไรที่จะยังคงใช้ได้? จากวิธีการเขียนโค้ดการรับประกันรหัสในผลที่ตามมาของข้อยกเว้นคืออะไร

หรือเป็นไปได้ว่ารหัสบางอย่างสามารถรับประกันได้ว่าจะไม่ทิ้ง (เช่นไม่มีกระบวนการใดที่ขาดหายไปในระบบปฏิบัติการ)

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

เทคนิคการเขียนโปรแกรม C ++ ต่างๆส่งเสริมการรับประกันข้อยกเว้น RAII (การจัดการทรัพยากรตามขอบเขต) จัดเตรียมกลไกในการเรียกใช้โค้ดการล้างข้อมูลและให้แน่ใจว่าทรัพยากรนั้นได้รับการปล่อยตัวทั้งในกรณีปกติและกรณีพิเศษ การทำสำเนาข้อมูลก่อนดำเนินการแก้ไขบนวัตถุทำให้สามารถกู้คืนสถานะของวัตถุนั้นได้หากการดำเนินการล้มเหลว และอื่น ๆ

คำตอบสำหรับคำถาม StackOverflow นี้ให้เหลือบไปที่ความยาวที่ยอดเยี่ยมโปรแกรมเมอร์ C ++ ไปเข้าใจโหมดความล้มเหลวทั้งหมดที่เป็นไปได้ที่อาจเกิดขึ้นกับรหัสของพวกเขาและพยายามที่จะรักษาความถูกต้องของสถานะโปรแกรมแม้จะล้มเหลว การวิเคราะห์ทีละบรรทัดของรหัส C ++ กลายเป็นนิสัย

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

การอ้างอิง: http://en.cppreference.com/w/cpp/language/exceptions#Exception_safety - ดูภายใต้ข้อยกเว้นด้านความปลอดภัย

C ++ มีความพยายามที่ล้มเหลวในการใช้ข้อมูลจำเพาะข้อยกเว้น การวิเคราะห์ในภายหลังในภาษาอื่น ๆ ระบุว่าข้อกำหนดข้อยกเว้นนั้นใช้ไม่ได้

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

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

การอ้างอิง: http://www.gotw.ca/publications/mill22.htm

เริ่มต้นด้วย C ++ 17 [[nodiscard]]สามารถใช้แอททริบิวนี้กับค่าส่งคืนฟังก์ชัน (ดู: https://stackoverflow.com/questions/39327028/can-ac-function-be-declared-such-that-the-return-value -cannot-be-ละเว้น )

ดังนั้นหากฉันทำการเปลี่ยนแปลงรหัสและแนะนำเงื่อนไขความล้มเหลวชนิดใหม่ (เช่นข้อยกเว้นชนิดใหม่) มันเป็นการเปลี่ยนแปลงที่ไม่สิ้นสุดหรือไม่ มันควรบังคับให้ผู้เรียกอัพเดตรหัสหรืออย่างน้อยต้องได้รับการเตือนเกี่ยวกับการเปลี่ยนแปลง?

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


"ในฐานะที่เป็นหนึ่งในการปรับเปลี่ยนการใช้งานของฟังก์ชั่น (เช่นมันจำเป็นต้องโทรไปยังฟังก์ชั่นที่แตกต่างกันซึ่งอาจทำให้เกิดข้อยกเว้นชนิดใหม่) การบังคับใช้ข้อกำหนดข้อยกเว้นแบบเข้มงวดหมายความว่าคุณต้องอัปเดตข้อมูลจำเพาะนั้นด้วย" - ดี ตามที่คุณควร สิ่งที่จะเป็นทางเลือก? ไม่สนใจข้อยกเว้นที่แนะนำใหม่หรือไม่
AxiomaticNexus

@AomaticomaticNexus ที่ตอบโดยการรับประกันข้อยกเว้น ในความเป็นจริงฉันโต้แย้งข้อกำหนดไม่สามารถเสร็จสมบูรณ์; รับประกันคือสิ่งที่เรามองหา บ่อยครั้งที่เราเปรียบเทียบประเภทข้อยกเว้นในความพยายามที่จะค้นหาว่าการรับประกันใดที่เสียหาย - เพื่อคาดเดาว่าการรับประกันแบบใดที่ยังใช้การได้อยู่ ข้อมูลจำเพาะข้อยกเว้นแสดงรายการบางประเภทที่คุณต้องตรวจสอบ แต่โปรดจำไว้ว่าในระบบที่ใช้ได้จริงรายการนั้นอาจไม่สมบูรณ์ ส่วนใหญ่เวลาที่มันบังคับให้คนที่จะใช้ทางลัดของ "กิน" ประเภทยกเว้นห่อไว้ในข้อยกเว้นอีกซึ่งจะทำให้ประเภทยกเว้นการตรวจสอบอย่างหนัก
rwong

@AxiomaticNexus ฉันไม่ได้โต้แย้งหรือต่อต้านการใช้ข้อยกเว้น การใช้ข้อยกเว้นโดยทั่วไปสนับสนุนให้มีคลาสยกเว้นฐานและบางคลาสยกเว้นที่ได้รับ ในขณะเดียวกันเราต้องจำไว้ว่ามีข้อยกเว้นประเภทอื่น ๆ ที่เป็นไปได้เช่นประเภทที่ถูกโยนจาก C ++ STL หรือไลบรารีอื่น ๆ อาจเป็นที่ถกเถียงกันอยู่ว่าสเปคข้อยกเว้นนั้นสามารถทำงานได้ในกรณีนี้: ระบุว่าข้อยกเว้นมาตรฐาน ( std::exception) และข้อยกเว้นพื้นฐานของคุณจะถูกโยนทิ้ง แต่เมื่อนำไปใช้กับโครงการทั้งหมดมันก็หมายความว่าทุกฟังก์ชั่นเดียวจะมีสเปคเดียวกันนี้: เสียงรบกวน
ร.

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

1
@rwong: ปัญหาใหญ่ที่มีการจัดการข้อยกเว้นในภาษาที่เป็นไปตามรูปแบบ C ++ นั้นcatchขึ้นอยู่กับประเภทของวัตถุยกเว้นเมื่อในหลาย ๆ กรณีสิ่งที่สำคัญไม่ได้เป็นสาเหตุโดยตรงของข้อยกเว้น แต่มันหมายถึงอะไร สถานะของระบบ น่าเสียดายที่ประเภทของข้อยกเว้นโดยทั่วไปไม่ได้บอกอะไรเลยว่ามันทำให้รหัสออกจากชิ้นส่วนของรหัสอย่างไม่ต่อเนื่องในลักษณะที่ทำให้วัตถุอยู่ในสถานะที่ได้รับการปรับปรุงบางส่วน (และไม่ถูกต้อง)
supercat

4

พิจารณานักพัฒนาที่เรียกใช้ฟังก์ชัน C () เขาไม่ตรวจสอบเอกสารดังนั้นจึงไม่ตรวจพบข้อยกเว้นใด ๆ การโทรไม่ปลอดภัย

มันปลอดภัยโดยสิ้นเชิง เขาไม่จำเป็นต้องจับข้อยกเว้นในทุก ๆ ที่เขาสามารถโยนลองในที่ที่เขาสามารถทำสิ่งที่มีประโยชน์เกี่ยวกับมันได้ มันไม่ปลอดภัยหากเขายอมให้มันรั่วไหลออกมาจากเกลียว แต่โดยทั่วไปก็ไม่ยากที่จะป้องกันไม่ให้เกิดขึ้น


ไม่ปลอดภัยเนื่องจากเขาไม่ได้คาดหวังว่าจะมีข้อยกเว้นC()เกิดขึ้นดังนั้นจึงไม่ป้องกันรหัสหลังจากการโทรถูกข้าม C()ถ้ารหัสที่จะต้องรับประกันว่าไม่แปรเปลี่ยนบางอย่างยังคงเป็นจริงรับประกันที่จะไปกะเทยที่ยกเว้นแรกออกมาของ ไม่มีสิ่งใดที่เป็นซอฟต์แวร์ที่ปลอดภัยยกเว้นอย่างสมบูรณ์แบบและแน่นอนที่สุดคือไม่เคยมีข้อยกเว้นใด ๆ
cmaster

1
@cmaster เขาไม่คาดหวังว่าจะมีข้อC()ผิดพลาดเกิดขึ้นเป็นความผิดพลาดครั้งใหญ่ เริ่มต้นใน C ++ คือฟังก์ชั่นใด ๆ ที่สามารถโยน - มันต้องมีความชัดเจนnoexcept(true)ในการบอกคอมไพเลอร์เป็นอย่างอื่น ในกรณีที่ไม่มีสัญญานี้โปรแกรมเมอร์จะต้องสมมติว่าฟังก์ชั่นสามารถโยนได้
Sjoerd

1
@cmaster นั่นเป็นความผิดของตัวเองที่โง่เขลาและไม่มีส่วนเกี่ยวข้องกับผู้แต่ง C () ความปลอดภัยยกเว้นเป็นสิ่งที่เขาควรเรียนรู้เกี่ยวกับมันและปฏิบัติตามมัน ถ้าเขาเรียกฟังก์ชั่นที่เขาไม่ทราบว่าเป็นข้อยกเว้นเขาควรจัดการกับสิ่งที่เกิดขึ้นถ้ามันพ่น หากเขาต้องการไม่มีข้อยกเว้นเขาควรหาการดำเนินการซึ่งก็คือ
DeadMG

@Sjoerd และ DeadMG: ในขณะที่มาตรฐานอนุญาตให้ฟังก์ชั่นใด ๆ ที่จะโยนข้อยกเว้นนั่นไม่ได้หมายความว่าโครงการจะต้องอนุญาตให้มีข้อยกเว้นในรหัสของพวกเขา หากคุณห้ามข้อยกเว้นจากรหัสของคุณเช่นเดียวกับหัวหน้าทีมของ OP ดูเหมือนว่ากำลังทำอยู่คุณไม่ต้องทำการเขียนโปรแกรมที่ปลอดภัยยกเว้น และถ้าคุณพยายามโน้มน้าวให้หัวหน้าทีมยอมให้มีการยกเว้นในโค้ดฐานที่ก่อนหน้านี้ไม่มีข้อยกเว้นมันจะมีC()ฟังก์ชั่นมากมายที่ทำลายการแสดงตนของข้อยกเว้น นี่เป็นสิ่งที่ไม่ฉลาดมากที่ต้องทำมันถึงวาระที่จะนำไปสู่ปัญหามากมาย
cmaster

@cmaster นี่เป็นโครงการใหม่ - ดูความคิดเห็นแรกเกี่ยวกับคำตอบที่ยอมรับ ดังนั้นจึงไม่มีฟังก์ชั่นที่มีอยู่ที่จะทำลายเนื่องจากไม่มีฟังก์ชั่นที่มีอยู่
Sjoerd

3

หากคุณกำลังสร้างระบบที่สำคัญลองทำตามคำแนะนำของหัวหน้าทีมและไม่ใช้ข้อยกเว้น นี่คือกฎ AV 208 ล็อกฮีดมาร์ตินร่วม Strike Fighter อากาศยานพาหนะ c ++ มาตรฐานการเข้ารหัส ในทางกลับกันแนวทางของMISRA C ++ นั้นมีกฎเฉพาะเกี่ยวกับข้อยกเว้นที่สามารถและไม่สามารถใช้ได้หากคุณกำลังสร้างระบบซอฟต์แวร์ที่สอดคล้องกับ MISRA

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

ในที่สุดฉันจะยืนยันว่าการออกแบบโดยการทำสัญญาและการเขียนโปรแกรมการป้องกันควบคู่กับการวิเคราะห์แบบคงที่มีความปลอดภัยสำหรับระบบซอฟต์แวร์ที่สำคัญกว่าข้อยกเว้น

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