แอตทริบิวต์ (Attributes) เป็นวิธีสมัยใหม่ใน C++ เพื่อทำให้โค้ดมาตรฐาน หากโค้ดรันบนคอมไพลอร์ต่างกัน Attributes ใช้ให้ข้อมูลเพิ่มเติมที่ใช้บังคับ เงื่อนไข (constraints), เพิ่มประสิทธิภาพ (optimization) และสร้างโค้ดเฉพาะ (specific code generation) หากจำเป็น
เหมือนคู่มือข้อมูลสำหรับคอมไพลอร์ เพื่อบังคับบางอย่างที่จะเพิ่มประสิทธิภาพของโค้ด Attributes ปรากฏครั้งแรกใน C++11 และเป็นส่วนสำคัญของภาษาโปรแกรมมาจนถึงปัจจุบัน นอกจากนี้ ทุกเวอร์ชันจะมีการปรับปรุงต่อเนื่องเพื่อทำให้มีพลังมากขึ้นและดีขึ้น
วิธีการกำหนด Attributes ใน C++
สำหรับ C++ เวอร์ชันต่างๆ ไวยากรณ์ในการกำหนด attributes จะต่างกัน
ไวยากรณ์สร้าง attribute ใน C++11:
[[attribute-list]]
ไวยากรณ์สร้าง attribute ใน C++17:
[[using attribute-namespace : attribute_list]]
ไวยากรณ์สร้าง attribute ใน C++20 (จะเผยแพร่เร็วๆ นี้):
[[contract-attriubute-token contract-level-identifier : expression]]
คุณสามารถใช้ attributes หลายตัวกับตัวแปร ฟังก์ชัน คลาสได้
ตอนนี้เรารู้แล้วว่า attributes คืออะไร ทำงานอย่างไร และกำยังไง มาดู attributes มาตรฐานที่มีใน C++ กัน
Attributes ที่เพิ่มใน C++11
noreturn - ใช้บอกคอมไพลอร์ว่าฟังก์ชันนี้ไม่คืนค่าใดๆ
Syntax
[[noreturn]]
ตัวอย่าง
[[noreturn]] void f();
ฟังก์ชันนี้จะไม่คืนค่า ไม่ว่าจะเป็น void ก็ตาม
Attribute noreturn เมื่อใช้ใน C++ จะทำให้คอมไพลอร์แจ้งเตือน (warning) หากมีบางอย่างผิดพลาดและโฟลว์ไม่กลับไปยังโค้ดที่เรียก เช่น กรณี infinite loop หรือ error
carries_dependency - ใช้กำหนด dependencies ทั้งหมดที่อยู่ใน release-consume และอนุญาตให้คอมไพลอร์เพิ่มประสิทธิภาพโดยไม่ผ่านคำสั่งที่ใช้หน่วยความจำไม่จำเป็น
Syntax
[[carries_dependency]]
ใช้หลักกับการประกาศฟังก์ชันหรือพารามิเตอร์เพื่อประกาศ dependencies
deprecated - ใช้กำหนด entity ที่ deprecated ในโค้ด การใช้ entity ที่ deprecated นี้ ยอมรับได้แต่ ไม่แนะนำ ให้ใช้
Syntax
[[deprecated]] [[deprecated (reason)]]
reason คือ สตริงที่ให้เหตุผลว่าทำไมถึง deprecated และให้ทางเลือกแทนสำหรับ entity ที่ deprecated
Entities ที่สามารถ deprecated ได้ ได้แก่ คลาส โครงสร้าง (structure) ยูเนียน (union) typedef-name สมาชิก static ฟังก์ชัน namespace การแจกแจง (enumeration)
fallthrough - ใช้บอกคอมไพลอร์ว่า fallthrough ไปยัง case ถัดไปเป็นเจตนาโดยเจตนารับรู้ ทำให้คอมไพลอร์ไม่เตือน fallthrough
Syntax
[[fallthrough]]
fallthrough อาจใช้ได้กับ switch เท่านั้น เนื่องจาก case ถัดไปถูกกำหนดไว้สำหรับมัน
nodiscard - ใช้สำหรับฟังก์ชันที่จะคืนค่า enumeration จะถูกเรียกจาก discarded value expression แทนการ cast เป็น void call คอมไพลอร์จะแจ้งเตือนสำหรับมันด้วย
Syntax
[[nodiscard]] [[nodiscard (reason)]] (เพิ่มใน C++20)
reason คือ สตริงที่ใช้ให้เหตุผลว่าทำไมไม่ควร discard ผลลัพธ์ และจะรวมอยู่ใน C++20
maybe_unused - ใช้บอกคอมไพลอร์ให้ปิดกั้นหรือกำจัด warning ที่แสดงในกรณีของ entities ที่ไม่ได้ใช้
Syntax
[[maybe_unused]]
Entities ที่สามารถประกาศ maybe_unused ได้ ได้แก่ คลาส โครงสร้าง ยูเนียน typedef-name สมาชิก static ฟังก์ชัน ตัวแปร การแจกแจง
likely, unlikely - ใช้กำหนดว่าเส้นทางทางเลือก (alternative path) มีโอกาสมากกว่าหรือน้อยกว่าเส้นทางการทำงานปัจจุบัน
Syntax
[[likely]] [[unlikely]]
โดยทั่วไปจะนำไปใช้กับ entities ที่เปลี่ยนโฟลว์ของโปรแกรม เช่น labels และ statements
no_unique_address - ใช้กำหนด data-member ที่ไม่จำเป็นต้องมีที่อยู่เฉพาะ ใช้โดยทั่วไปในกรณีของ non-static data members ที่การจัดสรรหน่วยความจำไม่จำเป็น
Syntax
[[no_unique_address]]
มีประโยชน์เมื่อคอมไพลอร์ต้องกำหนดตำแหน่งหน่วยความจำระหว่างตัวแปรปกติและ no_unique_address คอมไพลอร์จะให้ความสำคัญกับตัวแรก
optimize_for_synchronized - ใช้กำหนดว่านิยามของฟังก์ชันที่กำหนดต้องเพิ่มประสิทธิภาพสำหรับการเรียกใช้จาก synchronized statement
Syntax
[[optimize_for_synchronized]]
ฟังก์ชันที่กำหนดเป็น optimize_for_synchronized จะหลีกเลี่ยงการ serialize synchronized blocks
expects - ระบุเงื่อนไขที่จำเป็นสำหรับอาร์กิวเมนต์ของฟังก์ชัน เพื่อให้ฟังก์ชันทำงานได้
Syntax
[[expects : condition]]
condition กำหนดเงื่อนไขที่ต้องเป็นจริงเพื่อให้ฟังก์ชันทำงานได้
นี่คือ attributes ทั้งหมดที่กำหนดใน C++ ตั้งแต่ C++11 ถึง C++20 ตอนนี้มาดูว่า ทำไม attributes ถึงถูกใช้ในการเขียนโปรแกรม คือ attributes ที่เสนอแก้ปัญหาอะไร?
เพิ่มเงื่อนไขให้โค้ด - ในหลายกรณี attributes เพิ่มความหมายให้โค้ด ทำให้มันถูกต้องมากขึ้นและลดความพยายามเพิ่มเติม
ให้ข้อมูลการเพิ่มประสิทธิภาพเพิ่มเติมแก่คอมไพลอร์ - บาง attributes เช่น fallthrough, likely, maybe_unused ให้ข้อมูลแก่คอมไพลอร์เพื่อทำ optimization เฉพาะ
หลีกเลี่ยง warning และ errors - บางครั้งตรรกะของโปรแกรมเมอร์ขัดกับกติกาที่เข้มงวดของ C++ นี่คือกรณีที่บาง attributes ช่วยให้ผู้ใช้หลีกเลี่ยงหรือปิดกั้น warning ที่จะเกิดขึ้น