ดังที่คนอื่น ๆ ชี้ให้เห็นว่าassert
เป็นป้อมปราการสุดท้ายในการป้องกันความผิดพลาดของโปรแกรมเมอร์ที่ไม่ควรเกิดขึ้น พวกเขากำลังตรวจสติที่หวังว่าจะไม่ล้มเหลวทางซ้ายและขวาตามเวลาที่คุณจัดส่ง
นอกจากนี้ยังได้รับการออกแบบมาให้ละเว้นจากการสร้างรีลีสที่เสถียรไม่ว่าด้วยเหตุผลใดก็ตามที่นักพัฒนาอาจพบว่ามีประโยชน์: ความสวยงาม, ประสิทธิภาพและทุกสิ่งที่พวกเขาต้องการ มันเป็นส่วนหนึ่งของสิ่งที่แยกการสร้างการดีบักออกจากการสร้างการวางจำหน่ายและตามคำจำกัดความการสร้างการเปิดตัวนั้นจะปราศจากการยืนยันดังกล่าว ดังนั้นจึงมีการโค่นล้มของการออกแบบหากคุณต้องการปล่อย"การสร้างการปล่อยพร้อมกับยืนยันในสถานที่" แบบอะนาล็อกซึ่งจะเป็นความพยายามในการสร้างการปล่อยด้วย_DEBUG
คำจำกัดความของตัวประมวลผลล่วงหน้าและไม่มีการNDEBUG
กำหนดไว้ มันไม่ใช่งานสร้างที่แท้จริงอีกต่อไป
การออกแบบขยายไปถึงไลบรารีมาตรฐาน ในฐานะที่เป็นตัวอย่างพื้นฐานมากในหมู่คนจำนวนมากการใช้งานจำนวนมากstd::vector::operator[]
จะassert
เป็นการตรวจสุขภาพจิตเพื่อให้แน่ใจว่าคุณไม่ได้ตรวจสอบเวกเตอร์จากขอบเขต และไลบรารี่มาตรฐานจะเริ่มทำงานมากยิ่งแย่กว่านี้หากคุณเปิดใช้งานการตรวจสอบดังกล่าวในบิลด์รีลีส มาตรฐานของvector
ใช้งานoperator[]
และการเติม ctor ด้วยการยืนยันดังกล่าวที่รวมอยู่กับอาเรย์ไดนามิกแบบเก่ามักจะแสดงอาเรย์แบบไดนามิกเร็วขึ้นมากจนกว่าคุณจะปิดการใช้งานการตรวจสอบดังกล่าวดังนั้นพวกเขาจึงมักจะส่งผลกระทบต่อประสิทธิภาพในระยะไกล การตรวจสอบตัวชี้ที่ว่างเปล่าที่นี่และการตรวจสอบนอกขอบเขตนั้นอาจกลายเป็นค่าใช้จ่ายมหาศาลหากการตรวจสอบดังกล่าวถูกนำไปใช้นับล้านครั้งในทุกเฟรมในลูปที่สำคัญก่อนหน้ารหัสง่าย ๆ เช่นเดียวกับการยกเลิก
ดังนั้นคุณน่าจะต้องการเครื่องมือที่แตกต่างกันสำหรับงานและสิ่งที่ไม่ได้รับการออกแบบมาให้ตัดออกจาก build build หากคุณต้องการ build build ที่ดำเนินการตรวจสอบสติในพื้นที่สำคัญ สิ่งที่ฉันพบว่ามีประโยชน์ที่สุดคือการบันทึก ในกรณีนี้เมื่อผู้ใช้รายงานข้อผิดพลาดสิ่งต่าง ๆ จะง่ายขึ้นมากถ้าพวกเขาแนบบันทึกและบรรทัดสุดท้ายของบันทึกจะให้เบาะแสที่สำคัญแก่ฉันเกี่ยวกับข้อผิดพลาดที่เกิดขึ้นและสิ่งที่อาจเป็น จากนั้นเมื่อทำซ้ำขั้นตอนของพวกเขาในโครงสร้างการดีบักฉันก็อาจได้รับความล้มเหลวในการยืนยันและความล้มเหลวในการยืนยันนั้นยิ่งทำให้ฉันมีเงื่อนงำที่ยิ่งใหญ่ในการปรับปรุงเวลาของฉัน แต่เนื่องจากการบันทึกมีราคาค่อนข้างแพงฉันไม่ได้ใช้เพื่อใช้การตรวจสุขภาพจิตในระดับต่ำมากเช่นทำให้แน่ใจว่าอาร์เรย์ไม่สามารถเข้าถึงได้อย่างไร้ขอบเขตในโครงสร้างข้อมูลทั่วไป
แต่ในที่สุดและค่อนข้างเห็นด้วยกับคุณฉันเห็นกรณีที่สมเหตุสมผลซึ่งคุณอาจต้องการทดสอบสิ่งที่คล้ายกับ debug build ระหว่างการทดสอบอัลฟาตัวอย่างกับกลุ่มผู้ทดสอบ alpha กลุ่มเล็ก ๆ ที่พูดลงนาม NDA . อาจมีการปรับปรุงการทดสอบอัลฟาถ้าคุณมอบเครื่องทดสอบของคุณนอกเหนือจากการสร้างรุ่นเต็มพร้อมข้อมูลการดีบักที่แนบมาพร้อมกับคุณสมบัติการดีบัก / พัฒนาบางอย่างเช่นการทดสอบที่พวกเขาสามารถเรียกใช้และเอาท์พุท verbose มากขึ้นในขณะที่ใช้ซอฟต์แวร์ อย่างน้อยฉันก็เคยเห็น บริษัท เกมยักษ์ใหญ่บางแห่งทำสิ่งต่าง ๆ เช่นนั้นสำหรับอัลฟ่า แต่สำหรับบางอย่างเช่นการทดสอบอัลฟาหรือการทดสอบภายในที่คุณกำลังพยายามให้ผู้ทดสอบอย่างอื่นนอกเหนือจากการสร้างรีลีส หากคุณกำลังพยายามสร้างการวางจำหน่ายจริงตามนิยามแล้วไม่ควรมี_DEBUG
กำหนดไว้หรืออย่างอื่นที่สร้างความสับสนให้กับความแตกต่างระหว่างการสร้าง "debug" และ "release"
เหตุใดจึงต้องลบรหัสนี้ออกก่อนวางจำหน่าย การตรวจสอบไม่มากประสิทธิภาพท่อระบายน้ำและหากพวกเขาล้มเหลวมีปัญหาแน่นอนว่าฉันต้องการข้อความแสดงข้อผิดพลาดโดยตรงมากขึ้นเกี่ยวกับ
ดังที่ได้กล่าวไว้ข้างต้นการตรวจสอบนั้นไม่จำเป็นต้องเป็นเรื่องเล็กน้อยจากมุมมองด้านประสิทธิภาพ หลายคนมีแนวโน้มเล็กน้อย แต่อีกครั้งแม้แต่ lib มาตรฐานก็ใช้และอาจส่งผลกระทบต่อประสิทธิภาพการทำงานในรูปแบบที่ยอมรับไม่ได้สำหรับคนจำนวนมากในหลายกรณีถ้าพูดการเข้าถึงแบบสุ่มโดยstd::vector
ใช้เวลานานถึง 4 เท่าในสิ่งที่ควรจะเป็น เนื่องจากการตรวจสอบขอบเขตที่ไม่ควรจะล้มเหลว
ในอดีตทีมเราต้องทำให้เมทริกซ์และเวกเตอร์ไลบรารี่ของเราไม่รวมการยืนยันในเส้นทางที่สำคัญบางอย่างเพื่อให้ debug builds ทำงานได้เร็วขึ้นเพราะ asserts เหล่านั้นทำให้การคำนวณทางคณิตศาสตร์ช้าลงโดยเรียงตามลำดับความสำคัญ เริ่มต้นที่จะต้องให้เรารอ 15 นาทีก่อนที่เราจะสามารถสืบค้นรหัสดอกเบี้ยได้ เพื่อนร่วมงานของฉันต้องการลบจริงๆasserts
ทันทีเพราะพวกเขาพบว่าการทำเช่นนั้นสร้างความแตกต่างอย่างมหันต์ แต่เราตัดสินที่จะทำให้เส้นทางการดีบักที่สำคัญหลีกเลี่ยงพวกเขา เมื่อเราทำให้เส้นทางที่สำคัญเหล่านั้นใช้ข้อมูลเวกเตอร์ / เมทริกซ์โดยตรงโดยไม่ผ่านการตรวจสอบขอบเขตเวลาที่ต้องใช้ในการดำเนินการอย่างเต็มรูปแบบ (ซึ่งรวมมากกว่าแค่เวกเตอร์ / เมทริกซ์คณิตศาสตร์) ลดลงจากนาทีเป็นวินาที นั่นเป็นกรณีที่รุนแรง แต่แน่นอนว่าการยืนยันนั้นไม่ได้มีเพียงเล็กน้อยจากมุมมองด้านประสิทธิภาพเสมอไป
แต่ยังเป็นเพียงวิธีการasserts
ออกแบบ หากพวกเขาไม่ได้มีผลกระทบอย่างมากต่อบอร์ดฉันก็อาจจะชอบมันถ้าพวกเขาได้รับการออกแบบให้เป็นมากกว่าคุณลักษณะการสร้าง debug หรือเราอาจใช้vector::at
ซึ่งรวมถึงการตรวจสอบขอบเขตแม้กระทั่งในการสร้างและปล่อยขอบเขต การเข้าถึงเช่น (ยังมีผลงานยอดเยี่ยมจำนวนมาก) แต่ในปัจจุบันฉันพบว่าการออกแบบของพวกเขามีประโยชน์มากขึ้นเนื่องจากได้รับผลกระทบอย่างมากในกรณีของฉันในฐานะคุณลักษณะการดีบักแบบบิลด์เท่านั้นซึ่งไม่ได้ระบุไว้เมื่อNDEBUG
ถูกกำหนด สำหรับกรณีที่ฉันทำงานด้วยอย่างน้อยก็สร้างความแตกต่างอย่างมากสำหรับงานสร้างรุ่นยกเว้นการตรวจสอบสติที่ไม่ควรล้มเหลวตั้งแต่แรก
vector::at
เมื่อเทียบกับ vector::operator[]
ฉันคิดว่าความแตกต่างของสองวิธีนี้เป็นหัวใจของสิ่งนี้รวมถึงทางเลือก: ข้อยกเว้น vector::operator[]
โดยทั่วไปการใช้งานassert
เพื่อให้แน่ใจว่าการเข้าถึงนอกขอบเขตจะทำให้เกิดข้อผิดพลาดที่ทำซ้ำได้ง่ายเมื่อพยายามเข้าถึงเวกเตอร์จากขอบเขต แต่ผู้ใช้งานไลบรารี่ทำเช่นนี้โดยสันนิษฐานว่าจะไม่มีค่าใช้จ่ายเล็กน้อยในการสร้างรีลีสที่ดีที่สุด
ในขณะเดียวกันvector::at
มีให้ซึ่งมักจะไม่ออกจากขอบเขตการตรวจสอบและพ่นแม้ในรุ่นสร้าง แต่ก็มีโทษประสิทธิภาพการทำงานให้มันถึงจุดที่ฉันมักจะเห็นรหัสที่ไกลมากขึ้นโดยใช้กว่าvector::operator[]
vector::at
การออกแบบจำนวนมากของ C ++ สะท้อนถึงแนวคิดของ "จ่ายสำหรับสิ่งที่คุณใช้ / ต้องการ" และผู้คนจำนวนมากมักชอบoperator[]
ซึ่งไม่ได้กังวลกับขอบเขตการตรวจสอบในรุ่นสร้างตามความคิดที่พวกเขาสวม ไม่จำเป็นต้องตรวจสอบขอบเขตในงานสร้างที่ปรับปรุงแล้ว ทันใดนั้นหากการยืนยันถูกเปิดใช้งานในรุ่นบิลด์ประสิทธิภาพของทั้งสองนี้จะเหมือนกันและการใช้เวกเตอร์จะสิ้นสุดลงช้ากว่าอาร์เรย์แบบไดนามิกเสมอ ดังนั้นส่วนใหญ่ของการออกแบบและประโยชน์ของการยืนยันจึงขึ้นอยู่กับความคิดที่ว่าพวกเขามีอิสระในการสร้างรุ่น
release_assert
สิ่งนี้น่าสนใจหลังจากค้นพบความตั้งใจเหล่านี้ โดยปกติแล้วกรณีการใช้งานของทุกคนจะแตกต่างกันไป แต่ฉันคิดว่าฉันจะพบการใช้งานบางอย่างสำหรับrelease_assert
การตรวจสอบและจะพังซอฟต์แวร์ที่แสดงหมายเลขบรรทัดและข้อความแสดงข้อผิดพลาดแม้ในรุ่นที่วางจำหน่าย
มันจะเป็นกรณีที่คลุมเครือในกรณีของฉันที่ฉันไม่ต้องการให้ซอฟต์แวร์กู้คืนได้อย่างสง่างามเช่นถ้ามีข้อยกเว้นเกิดขึ้น ฉันต้องการให้มันเกิดความผิดพลาดแม้ในกรณีที่ปล่อยเพื่อให้ผู้ใช้สามารถได้รับหมายเลขบรรทัดเพื่อรายงานเมื่อซอฟต์แวร์พบสิ่งที่ไม่ควรเกิดขึ้นยังอยู่ในขอบเขตของสติตรวจสอบข้อผิดพลาดของโปรแกรมเมอร์ไม่ใช่ข้อผิดพลาดอินพุตภายนอกเช่น ยกเว้น แต่ราคาถูกพอที่จะทำได้โดยไม่ต้องกังวลเกี่ยวกับค่าใช้จ่ายในการเปิดตัว
จริงๆแล้วมีบางกรณีที่ฉันจะพบความผิดพลาดอย่างหนักที่มีหมายเลขบรรทัดและข้อความแสดงข้อผิดพลาดที่ดีกว่าที่จะกู้คืนอย่างสง่างามจากข้อยกเว้นโยนซึ่งอาจมีราคาถูกพอที่จะเก็บไว้ในรุ่น และมีบางกรณีที่ไม่สามารถกู้คืนจากข้อยกเว้นได้เช่นข้อผิดพลาดที่พบเมื่อพยายามกู้คืนจากข้อยกเว้นที่มีอยู่ ที่นั่นฉันจะพบว่าเหมาะสมอย่างสมบูรณ์แบบสำหรับ a release_assert(!"This should never, ever happen! The software failed to fail!");
และโดยธรรมชาติที่จะสกปรกราคาถูกเนื่องจากการตรวจสอบจะดำเนินการภายในเส้นทางที่พิเศษในตอนแรกและจะไม่เสียค่าใช้จ่ายใด ๆ ในเส้นทางการดำเนินการตามปกติ