“ พิษต่อฟังก์ชัน” ใน C ++ หมายความว่าอย่างไร?


96

ในตอนท้ายของการพูดคุย"แนะนำconstexpr"ของ Scott Schurr ที่ CppConเขาถามว่า "มีวิธีทำให้ฟังก์ชันเป็นพิษหรือไม่"? จากนั้นเขาอธิบายว่าสิ่งนี้สามารถทำได้ (แม้ว่าจะเป็นวิธีที่ไม่ได้มาตรฐาน) โดย:

  1. วางthrowในconstexprฟังก์ชั่น
  2. การประกาศยังไม่ได้รับการแก้ไข extern const char*
  3. การอ้างถึงสิ่งที่ยังไม่ได้แก้ไขexternในไฟล์throw

ฉันรู้สึกว่าฉันไม่ได้อยู่ในส่วนลึกของฉันที่นี่ แต่ฉันอยากรู้:

  • "พิษต่อหน้าที่" หมายความว่าอย่างไร?
  • ความสำคัญ / ประโยชน์ของเทคนิคที่เขาสรุปคืออะไร?

1
ไม่เคยได้ยินเกี่ยวกับคำนั้นโปรดชี้แจงด้วยตัวอย่างสั้น ๆ !
πάνταῥεῖ

6
@ πάνταῥεῖฉันเพิ่งชี้แจง คำนี้ 'รู้จักกันอย่างแพร่หลายในแวดวงเล็ก ๆ '
SergeyA

4
เขากำลังพูดถึงการตรวจสอบว่าทุกการเรียกใช้constexprฟังก์ชันได้รับการประเมินในเวลาคอมไพล์
TC

@TC Right - เขากล่าวว่าconstexprฟังก์ชันสามารถใช้ได้ทั้งในเวลาคอมไพล์หรือในขณะทำงาน แล้วนี่เป็นวิธีบังคับไม่ให้ใช้ตอนรัน? เมื่อนั้นมีประโยชน์?
sudo ทำการติดตั้ง

3
โดยเฉพาะอย่างยิ่งใน C ++ 11 constexprฟังก์ชันมักจะไม่ใช่การใช้งานที่มีประสิทธิภาพสูงสุดเนื่องจากมีข้อ จำกัด ดังนั้นจึงอาจไม่ต้องการให้มีการประเมินในขณะทำงาน หรืออาจเป็นกรณีข้อผิดพลาด (ตามตัวอย่าง)
TC

คำตอบ:


106

โดยทั่วไปหมายถึงการทำให้ฟังก์ชันไม่สามารถใช้งานได้เช่นหากคุณต้องการห้ามการใช้การจัดสรรแบบไดนามิกในโปรแกรมคุณอาจ "วางยาพิษ" ให้mallocฟังก์ชันนั้นไม่สามารถใช้งานได้

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

ดังนั้นเขาจึงพูดถึงฟังก์ชัน "วางยาพิษ" ที่ทำให้ไม่สามารถเรียกใช้ได้ในขณะรันไทม์ดังนั้นจึงสามารถเรียกใช้ได้เฉพาะในนิพจน์คงที่เท่านั้น เทคนิคคือการมีสาขาในฟังก์ชันซึ่งจะไม่ถูกนำมาใช้เมื่อถูกเรียกในบริบทเวลาคอมไพล์และทำให้สาขานั้นมีสิ่งที่จะทำให้เกิดข้อผิดพลาด

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

เนื่องจากสัญลักษณ์ที่ไม่ได้กำหนดไม่ใช่ "odr-used" ในการเรียกใช้ฟังก์ชันเวลาคอมไพล์ในทางปฏิบัติคอมไพลเลอร์จะไม่สร้างการอ้างอิงถึงสัญลักษณ์ดังนั้นจึงไม่เป็นไรที่ไม่ได้กำหนด

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

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

NB ประสิทธิภาพของฟังก์ชัน constexpr ที่ใช้ในเวลาคอมไพล์นั้นไม่สำคัญมากนักเนื่องจากไม่มีค่าใช้จ่ายในการรันไทม์อยู่แล้ว อาจทำให้การคอมไพล์ของคุณช้าลงโดยการทำให้คอมไพเลอร์ทำงานพิเศษ แต่จะไม่มีต้นทุนประสิทธิภาพรันไทม์ใด ๆ


1
ฉันอ่านข้อความในสไลด์ แต่ไม่เห็นความเชื่อมโยงกับคำที่เขาใช้ เห็นได้ชัดว่าตอนนี้คุณได้อธิบายแล้ว แต่ตอนนั้นฉันไม่เห็น ขอบคุณมากสำหรับคำตอบที่ยอดเยี่ยม - ฉันชอบเว็บไซต์นี้
sudo ทำการติดตั้ง

@PravasiMeet ถามคำถามของคุณเองอย่าจี้ความคิดเห็นของคำถามของคนอื่นเกี่ยวกับสิ่งที่แตกต่าง วิธีแก้ปัญหาง่ายๆคือการกำหนดเป็นลบในทุกหน่วยการแปลหรือแทนที่ด้วยคำจำกัดความของคุณเองที่อ้างอิงสัญลักษณ์ที่ไม่ได้กำหนด
Jonathan Wakely

17

ตัวระบุ 'การเป็นพิษ' หมายความว่าการอ้างอิงถึงตัวระบุใด ๆ หลังจาก 'การเป็นพิษ' เป็นข้อผิดพลาดของฮาร์ดคอมไพเลอร์ ตัวอย่างเช่นอาจใช้เทคนิคนี้สำหรับการเลิกใช้งานแบบยาก (เลิกใช้งานฟังก์ชันแล้วห้ามใช้!)

ใน GCC ประเพณีที่มี pragma #pragma GCC poisonสำหรับนี้:


1
ใช่ แต่ไม่ตรงกับความหมายที่ใช้ในการพูดคุยนั้น
TC

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