- C++26 เสร็จสิ้นทางเทคนิคอย่างเป็นทางการ โดยมีฟีเจอร์หลัก 4 ด้าน ได้แก่ reflection, การเสริมความปลอดภัยของหน่วยความจำ, contracts, std::execution
- compile-time reflection คือเอนจินนามธรรมที่ทรงพลังที่สุดในประวัติศาสตร์ C++ นับตั้งแต่มีการนำ template เข้ามา ทำให้ภาษาอธิบายตัวเองและสร้างโค้ดได้
- เพียงแค่ คอมไพล์ใหม่ โค้ด C++ เดิมด้วย C++26 ก็สามารถกำจัดพฤติกรรมไม่กำหนดแน่ชัด (UB) จากตัวแปรภายในฟังก์ชันที่ยังไม่ถูกกำหนดค่าเริ่มต้นได้ และ standard library ที่เสริมความแข็งแกร่งแล้วจะรับประกัน bounds safety
- จากผลการนำไปใช้งานภายใน Google พบว่า แก้บั๊กได้มากกว่า 1,000 รายการ และวัดผลได้ว่า segfault ในระบบโปรดักชันลดลง 30%
- คาดว่าผู้พัฒนาคอมไพเลอร์จะรองรับอย่างรวดเร็ว โดย GCC ได้รวม reflection และ contracts เข้า trunk แล้ว
C++26 เสร็จสมบูรณ์: รุ่นที่สำคัญที่สุดนับตั้งแต่ C++11
- ในการประชุมคณะกรรมการ ISO C++ ที่จัดขึ้น ณ ครอยดอน กรุงลอนดอน สหราชอาณาจักร งานทางเทคนิคของ C++26 ได้ เสร็จสมบูรณ์ขั้นสุดท้าย
- มีผู้เข้าร่วมประมาณ 210 คน (เข้าร่วมในสถานที่ 130 คน และผ่าน Zoom 80 คน) พร้อมผู้แทนทางการจาก 24 ประเทศ
- เวลาส่วนใหญ่ของการประชุมถูกใช้ไปกับการจัดการ ความเห็นระหว่างประเทศ 411 รายการ (ขั้น CD) ที่ได้รับในช่วงฤดูร้อน
- มุ่งเน้นการเก็บรายละเอียดและปรับความสมบูรณ์ขั้นสุดท้าย โดยไม่มีการเพิ่มหรือลบฟีเจอร์ใหม่
- C++26 ที่ปิดงานในที่ประชุมครั้งนี้ได้เข้าสู่ขั้นตอนจัดทำเอกสารฉบับสุดท้ายเพื่อการ ลงคะแนนรับรองระดับนานาชาติ (DIS)
4 ฟีเจอร์หลักของ C++26
(1) Reflection
- เป็น การอัปเกรดครั้งใหญ่ที่สุดในประวัติศาสตร์การพัฒนา C++ นับตั้งแต่มีการคิดค้น template โดยทำให้ภาษาสามารถอธิบายตัวเองและสร้างโค้ดได้
- ในเดือนมิถุนายน 2025 คณะกรรมการ C++ ได้บรรจุ compile-time reflection ลงในร่าง C++26 ถือเป็นจุดเปลี่ยนสำคัญในประวัติศาสตร์ของภาษา
- มีการอธิบายว่าเป็น "เอนจินใหม่ที่ทรงพลังที่สุดสำหรับการแสดง abstraction อย่างมีประสิทธิภาพ และคงต้องใช้เวลาอีก 10 ปีข้างหน้าเพื่อค้นพบว่าเจ้าจรวดลำนี้ทำอะไรได้บ้าง"
(2) การเสริมความปลอดภัยของหน่วยความจำ
- เพียง คอมไพล์ใหม่เท่านั้น ก็สามารถกำจัดหมวดหมู่ทั้งหมดของ UB จากการอ่านตัวแปรภายในฟังก์ชันที่ยังไม่ถูกกำหนดค่าเริ่มต้นในโค้ด C++ เดิมได้ใน C++26
- มีการทำให้ Hardened Standard Library เป็นมาตรฐาน เพื่อรับประกัน bounds safety ของชนิดข้อมูลหลักอย่าง vector, span, string และ string_view
- วัดได้ว่ามี performance overhead เฉลี่ยเพียง 0.3% (ต่ำกว่า 1%)
- ถูกนำไปใช้แล้วกับโค้ดหลายร้อยล้านบรรทัดบนแพลตฟอร์มของ Apple และบริการของ Google
- ตัวเลขผลลัพธ์จากการใช้งานภายใน Google:
- แก้ไขบั๊กแล้ว มากกว่า 1,000 รายการ
- คาดว่าจะช่วย ป้องกันบั๊กได้ 1,000~2,000 รายการต่อปี
- อัตราการเกิด segfault ลดลง 30% ทั่วทั้งระบบโปรดักชัน
- จากโค้ด C++ ทั้งหมดของ Google มีบริการที่ opt-out แบบเต็มรูปแบบเพียง 5 บริการ และมีจุดที่ใช้ API การเข้าถึงแบบไม่ปลอดภัยเพียง 7 จุด
(3) Contracts: pre, post, contract_assert
- C++26 เพิ่ม ฟีเจอร์ contracts ระดับภาษา — รองรับ precondition, postcondition และคำสั่ง assertion ในการประกาศฟังก์ชัน
- ถูกประเมินว่าเป็นความสามารถที่ทรงพลังกว่า assert macro ของ C อย่างมาก
- ผลการลงคะแนนรับ contracts:
- กุมภาพันธ์ 2025 (รวมเข้ากับ working draft): เห็นด้วย 100, ไม่เห็นด้วย 14, งดออกเสียง 12
- มีนาคม 2026 (ยืนยัน C++26 ขั้นสุดท้าย): เห็นด้วย 114, ไม่เห็นด้วย 12, งดออกเสียง 3
- แม้จะยังมีข้อกังวลเชิงเทคนิคจากผู้เชี่ยวชาญบางส่วนในคณะกรรมการ แต่ก็มีการหารืออย่างเพียงพอผ่านการประชุม 3 ครั้งและการประชุมทางโทรศัพท์หลายรอบ
- ก่อนการประชุมก่อนเดือนพฤศจิกายน 2025 ได้แก้ไข บั๊ก 2 รายการ ในสเปก contracts โดยสะท้อนข้อเสนอแนะที่ได้รับ
(4) std::execution (Sender/Receiver)
- เป็น โมเดลแบบอะซิงโครนัส ของ C++ และเป็นเฟรมเวิร์กแบบรวมศูนย์สำหรับการแสดงและควบคุม concurrency กับ parallelism
- มีคุณสมบัติด้านความปลอดภัยที่ช่วยให้เขียน structured concurrency (concurrency ที่มีอายุการใช้งานซ้อนกันอย่างเคร่งครัด) ได้ง่าย จึงช่วยป้องกัน data race ในเชิงโครงสร้าง
- ข้อควรระวัง: ขณะนี้เอกสารประกอบยังไม่เพียงพอ และไลบรารีแบบ "fingers-and-toes" ยังไม่พร้อม ทำให้การนำไปใช้ยากกว่าฟีเจอร์ C++ อื่น ๆ
- อาจต้องอาศัยความช่วยเหลือจากผู้เชี่ยวชาญที่คุ้นเคยอยู่แล้ว และอาจต้องเขียน adapter library เพื่อเชื่อมกับโค้ดอะซิงโครนัสเดิม
เหตุผลที่คาดว่า C++26 จะถูกนำไปใช้อย่างรวดเร็ว
- เป็น ชุดฟีเจอร์ที่มีความต้องการสูงที่สุดนับตั้งแต่ C++11 โดยมีทั้ง reflection และการเสริมความปลอดภัยที่นักพัฒนา C++ ส่วนใหญ่จะใช้ในงานประจำวัน
- มีการประเมินว่าฟีเจอร์อย่าง parallel STL, concepts, coroutines และ modules ใน C++17, C++20, C++23 ไม่ได้ส่งผลกว้างขวางต่อผู้พัฒนา C++ ทุกคนเท่ากับ C++11
- GCC และ Clang ได้คงสถานะ ติดตั้งใช้งานล่วงหน้าราวสองในสามของฟีเจอร์ ตลอดช่วงการพัฒนา C++26
- GCC ได้ รวม reflection และ contracts เข้า trunk แล้ว และรอการออกรีลีส
เริ่มงาน C++29: ยกระดับความปลอดภัยหน่วยความจำต่อ
- ในการประชุมครั้งนี้มีการ รับรองกำหนดการของ C++29 ด้วย โดยยังคงรอบการออกรุ่นทุก 3 ปี
- ประเด็นหลักของ C++29 ถูกกำหนดให้เป็น การเสริม type safety และ memory safety เพิ่มเติม
- กำลังพิจารณาข้อเสนอเพิ่มเติมเพื่อลดพฤติกรรมไม่กำหนดแน่ชัด (UB) ลงอีก
- SG23 (กลุ่มย่อยด้านความปลอดภัยและความมั่นคง) กำลังดำเนินงานโดยอิงจาก P3984 type safety profile ของ Bjarne Stroustrup และกรอบ general profile ของ Gabriel Dos Reis
- Oliver Hunt จาก Apple ได้นำเสนอ P4158R0 "C++ Subsetting and Restriction for Memory Safety"
- ใช้แนวทาง subset-of-superset กับโค้ดของ WebKit ที่มี มากกว่า 4 ล้านบรรทัด
- มีรายงานว่า "สามารถปิดกั้นคลาสของช่องโหว่ได้จำนวนมาก และนโยบายปัจจุบันน่าจะป้องกัน exploit ส่วนใหญ่ในอดีตได้"
- ประเด็น memory safety ถูกหารืออย่างลึกซึ้งทั้งในช่วงเย็นวันพุธที่มีสมาชิกคณะกรรมการมากกว่าครึ่งเข้าร่วม และในเซสชันเฉพาะ EWG ช่วงบ่ายวันศุกร์ที่มีผู้เข้าร่วมราว 90 คน
- ไลบรารีปริมาณและหน่วย (P3045R7 "Quantities and units library") มีความคืบหน้าจาก SG6 และ SG18 ไปยัง LEWG (กลุ่มย่อยหลักด้านวิวัฒนาการไลบรารี)
กำหนดการถัดไป
- การประชุมอีก 2 ครั้งถัดไปมีกำหนดจัดที่ เบอร์โน สาธารณรัฐเช็ก (มิถุนายน) และ บูซิออส ริโอเดจาเนโร บราซิล (พฤศจิกายน)
- ทั้งสองการประชุมจะเริ่ม งานเพิ่มฟีเจอร์ลงใน working draft ของ C++29
- ตั้งแต่ตอนนี้จนถึงการประชุมครั้งถัดไป ได้มีการกำหนดการประชุมทางไกลของกลุ่มย่อยจำนวนมากไว้แล้ว
7 ความคิดเห็น
zzz
ความคิดเห็นบน Hacker News
รู้สึกเสียดายที่ฟีเจอร์ Contracts ถูกบรรจุเข้าเป็นมาตรฐานของ C++
มันให้ความรู้สึกเหมือนเพิ่มความซับซ้อนเข้าไปอีกในภาษาที่ซับซ้อนจนแทบถึงขีดจำกัดอยู่แล้ว
แม้แต่ Bjarne Stroustrup ก็ยังอธิบายฟีเจอร์นี้ว่าเป็น “การออกแบบที่ยังไม่สมบูรณ์และถูกทำให้พองโตแบบกรรมการ”
ตัวฟีเจอร์เองก็มีจุดเสี่ยงแบบ footgun อยู่มาก เลยคิดว่ายังให้เหตุผลรองรับได้ไม่มากนัก
แต่ไม่มีใครสนใจเลย
เอกสารที่เกี่ยวข้องอยู่ ที่นี่
มันเป็นองค์ประกอบสำคัญในการผสานรวมกับ การพิสูจน์เชิงรูปนัย (proof assistant) แบบ Ada หรือ Rust เพื่อให้ทำการตรวจสอบแบบสถิตแทนการทดสอบได้
Ada Spark เป็นตัวอย่างที่ควรดู
ตัวอย่างแรกใน เอกสาร cppreference กลับเป็นเคสยกเว้นที่มีการเปลี่ยนสถานะ
ไวยากรณ์ก็ไม่ค่อยตรงไปตรงมา
เช่น รูปแบบ
asserts_pre(num >= 0)น่าจะชัดเจนกว่าpre(num >= 0)มากแต่ดูเหมือนจะให้ความสำคัญกับความสั้นกระชับมากกว่า
มากกว่าจะเพิ่มความซับซ้อน มันคือการรวมสิ่งที่แต่ละคนทำกันเองเพื่อเพิ่มการทำงานร่วมกันได้
กลับกัน ฟีเจอร์อย่าง Reflection ต่างหากที่ดูเพิ่มความซับซ้อนมากกว่า
ในฐานะนักพัฒนา C#, Java มีเรื่องที่สงสัย
อยากรู้ว่าทุกวันนี้เขาสร้าง แอปพลิเคชัน ประเภทไหนด้วย C++ กันบ้าง
ไม่ค่อยมีโอกาสได้ยินว่าจริง ๆ แล้วมันถูกใช้แก้ปัญหาแบบไหน
การ นิยามใหม่ของ “erroneous behavior” สำหรับตัวแปรที่ยังไม่ได้กำหนดค่าเป็นเรื่องที่น่าสนใจ
ตาม เอกสารมาตรฐาน มันมีต้นทุนตอนรันไทม์เพิ่มขึ้น
และสามารถใช้แอตทริบิวต์
[[indeterminate]]เพื่อย้อนกลับไปเป็น undefined behavior ได้ถ้าต้องการไม่กำหนดค่าจริง ๆ ต้องเขียนให้ชัดอย่าง
int x = void;แทบไม่มีทางเขียนแบบนั้นโดยพลาดได้
[[indeterminate]]ถึงต้องย้อนกลับไปเป็น UB (Undefined Behavior) อีกบางโปรเจกต์ก็คงยังชอบการกำหนดค่าเริ่มต้นด้วยมืออยู่ดี
[[indeterminate]]ในโค้ดภายหลังก็น่ากลัวแล้วสุดท้ายคงเสียเวลาไปกับการหาความหมาย หรือไม่ก็ต่อไปก็แค่เมินมันไป
มันทำให้นึกถึงประสบการณ์กับ Rust ที่มี generic และ trait เยอะจนอ่านโค้ดยาก
เคยทำงานอยู่ในทีม C++ ของ MS ช่วงยุค 90
ตอนนั้นคิดว่า RTTI คือขีดจำกัดของระบบ reflection ที่ C++ จะมีได้แล้ว
พัฒนาการในตอนนี้เลยน่าทึ่งมาก
การไปจัดประชุมที่ Croydon แล้วไม่ยอมให้ใครออกไปจนกว่าจะเซ็นชื่อ ถือเป็น กลยุทธ์ที่แยบยล พอตัว
ไม่อยากทำงานที่นั่นอีกเป็นครั้งที่สอง
สงสัยว่าสถานะการรองรับ C++26 ของ GCC กับ Clang ไปถึงไหนแล้ว
GCC รวม reflection และ contracts เข้า trunk แล้ว แต่ก็อยากรู้ว่า Clang ไปถึงระดับไหน
ส่วนใน หน้าของ GCC แสดงเป็น “yes”
ใช้งานได้แล้วใน Compiler Explorer และถูกนำไปใช้เพื่อเพิ่ม reflection ให้ simdjson
ยังสงสัยว่าการ เปลี่ยนแปลงระบบโมดูล ในมาตรฐานครั้งนี้จะทำให้มันถูกใช้งานแพร่หลายขึ้นจริงหรือไม่
เหตุผลที่ Cargo ของ Rust เหนือกว่า C++ อย่างชัดเจนก็อยู่ตรงนี้
การที่เพิ่ม dependency ด้วยคำสั่ง
cargo addบรรทัดเดียวไม่ได้ กำลังผลักคนรุ่นใหม่ให้ออกห่างถ้า CMake รับเอาโมเดลคอมไพล์สองขั้นของ Clang ไปใช้ ความเร็วในการบิลด์จะดีขึ้นมาก
และเมื่อนั้นเองโมดูลจึงจะเริ่มถูกนำไปใช้จริงจัง
แทบไม่มีโอกาสจะกลายเป็นกระแสหลัก
มีฟีเจอร์ใหม่เยอะเกินไปจนตามไม่ทัน
ระบบบิลด์ก็ยุ่งเหยิง และ ไฟล์ header ก็ควรหายไปได้แล้ว
แม้จะไม่เกี่ยวกับประเด็นหลัก แต่คำว่า “London Croydon” ฟังดูแปลก
ปกติไม่ควรพูดว่า “Croydon, London” มากกว่าหรือ?
เวลาวางแผนการเดินทาง การอ่านจากพื้นที่ใหญ่ไปเล็กมักจะเป็นธรรมชาติกว่า
เหตุผลที่เขียนว่า “London, Croydon” อาจเป็นเพราะต้องการให้ความรู้สึกว่า “ไปประชุมที่ลอนดอน”
ส่วน “Croydon, London” จะให้ความรู้สึกประมาณ “จัดที่ Croydon ชานลอนดอน” เลยดูไม่เท่ากว่า — เป็นการแซวเล่น
ก็มีปฏิกิริยาเชิง ประชดประชัน ทำนองว่า “ออกมาทันก่อนภาษาจะถูกเลิกใช้พอดี”
ถ้า C++29 โฟกัสแค่ การปรับปรุงคุณภาพและเกลาฟีเจอร์เดิม ชุมชนก็คงไม่ได้ไม่พอใจอะไรมาก
random()แบบบรรทัดเดียวใน C++29 ก็น่าจะพอใจแล้วกว่ามาตรฐาน C++ จะออกมาแล้วถูกนำไปใช้จริงในอุตสาหกรรม ก็ต้องผ่านไปเกิน 5 ปีถึงจะเริ่มมีบรรยากาศการยอมรับกันแบบค่อยเป็นค่อยไป.. แม้จะน่าสนใจ แต่ก็เหมือนของที่ได้แค่มองตาปริบ ๆ ฮือฮือ
แทนที่จะเพิ่มฟีเจอร์เพื่อความปลอดภัยของหน่วยความจำ แค่ห้าม dangling pointer หรือ mutable reference ก็ช่วยเพิ่มความปลอดภัยของหน่วยความจำได้แล้ว แต่กลับยิ่งเพิ่มความซับซ้อนของโค้ดด้วยการเพิ่มฟีเจอร์เสียมากกว่า
กว่าจะย้ายไป Rust ได้อย่างยากลำบาก ฟีเจอร์ที่รอคอยอยู่ไม่น้อยก็ถูกใส่เข้ามาในมาตรฐาน C++26 อย่างเป็นทางการ ถือว่าน่ายินดีครับ แต่ก็คงไม่ย้ายกลับไป C++ อีกหรอก... 555
เรื่องที่เกี่ยวกับแพ็กเกจก็มีออกมาทางฝั่ง CMake อยู่เหมือนกันครับ..
https://www.kitware.com/common-package-specification-is-out-the-gate/
contractเป็นฟีเจอร์ที่รอคอยจริง ๆ ในที่สุดก็มาเสียที