ดังนั้นสิ่งที่ชั้นไม่กลายเป็นซับซ้อนเกินไปที่จะไม่เปลี่ยนรูป?
ในความคิดของฉันมันไม่คุ้มค่าที่จะสร้างชั้นเรียนขนาดเล็กที่ไม่เปลี่ยนแปลงในภาษาเช่นเดียวกับที่คุณแสดง ฉันใช้เล็ก ๆที่นี่และไม่ซับซ้อนเพราะแม้ว่าคุณจะเพิ่มสิบฟิลด์ลงในคลาสนั้นและมันเป็นการดำเนินการที่น่าทึ่งจริง ๆ ฉันสงสัยว่ามันจะใช้เวลากิโลไบต์เป็นเมกะไบต์เพียงอย่างเดียว คลาสสามารถทำสำเนาราคาถูกของวัตถุทั้งหมดเพื่อหลีกเลี่ยงการแก้ไขต้นฉบับหากต้องการหลีกเลี่ยงการก่อให้เกิดผลข้างเคียงภายนอก
โครงสร้างข้อมูลถาวร
NamedThings
ฉันพบการใช้งานส่วนบุคคลสำหรับการเปลี่ยนไม่ได้เป็นใหญ่โครงสร้างข้อมูลกลางที่รวบรวมพวงของข้อมูลที่เล็กเช่นกรณีของชั้นเรียนที่คุณกำลังแสดงเช่นหนึ่งที่ร้านล้าน โดยเป็นของโครงสร้างข้อมูลถาวรซึ่งไม่เปลี่ยนรูปและอยู่ด้านหลังส่วนต่อประสานที่อนุญาตให้เข้าถึงแบบอ่านอย่างเดียวเท่านั้นองค์ประกอบที่เป็นของคอนเทนเนอร์จะไม่เปลี่ยนรูปโดยไม่ต้องมีคลาสองค์ประกอบ ( NamedThing
) ที่ต้องจัดการกับมัน
สำเนาถูก
โครงสร้างข้อมูลถาวรช่วยให้พื้นที่ของมันจะถูกแปลงและทำให้เป็นเอกลักษณ์หลีกเลี่ยงการแก้ไขต้นฉบับโดยไม่ต้องคัดลอกโครงสร้างข้อมูลทั้งหมด นั่นคือความงามที่แท้จริงของมัน หากคุณต้องการเขียนอย่างไร้เดียงสาฟังก์ชั่นที่หลีกเลี่ยงผลข้างเคียงที่ป้อนโครงสร้างข้อมูลที่ใช้หน่วยความจำกิกะไบต์และปรับเปลี่ยนค่าหน่วยความจำของเมกะไบต์เท่านั้นคุณต้องคัดลอกสิ่งที่น่ากลัวทั้งหมดเพื่อหลีกเลี่ยงการสัมผัสอินพุตและส่งคืนใหม่ เอาท์พุต เป็นการคัดลอกกิกะไบต์เพื่อหลีกเลี่ยงผลข้างเคียงหรือทำให้เกิดผลข้างเคียงในสถานการณ์นั้นทำให้คุณต้องเลือกระหว่างตัวเลือกที่ไม่พึงประสงค์สองตัว
ด้วยโครงสร้างข้อมูลถาวรช่วยให้คุณสามารถเขียนฟังก์ชั่นดังกล่าวและหลีกเลี่ยงการทำสำเนาของโครงสร้างข้อมูลทั้งหมดเพียงแค่ต้องการหน่วยความจำเพิ่มอีกเมกะไบต์สำหรับเอาท์พุทหากฟังก์ชันของคุณเปลี่ยนหน่วยความจำของเมกะไบต์เท่านั้น
ภาระ
สำหรับภาระมีอย่างน้อยหนึ่งทันทีในกรณีของฉัน ฉันต้องการผู้สร้างที่ผู้คนกำลังพูดถึงหรือ "ชั่วคราว" ในขณะที่ฉันเรียกพวกเขาเพื่อให้สามารถแสดงการเปลี่ยนแปลงโครงสร้างข้อมูลขนาดใหญ่นั้นได้อย่างมีประสิทธิภาพโดยไม่ต้องสัมผัส รหัสเช่นนี้:
void transform_stuff(MutList<Stuff>& stuff, int first, int last)
{
// Transform stuff in the range, [first, last).
for (; first != last; ++first)
transform(stuff[first]);
}
... จากนั้นจะต้องมีการเขียนเช่นนี้:
ImmList<Stuff> transform_stuff(ImmList<Stuff> stuff, int first, int last)
{
// Grab a "transient" (builder) list we can modify:
TransientList<Stuff> transient(stuff);
// Transform stuff in the range, [first, last)
// for the transient list.
for (; first != last; ++first)
transform(transient[first]);
// Commit the modifications to get and return a new
// immutable list.
return stuff.commit(transient);
}
แต่เพื่อแลกกับโค้ดพิเศษสองบรรทัดตอนนี้ฟังก์ชั่นนี้ปลอดภัยในการโทรข้ามเธรดที่มีรายการดั้งเดิมเหมือนกันมันไม่ทำให้เกิดผลข้างเคียง ฯลฯ นอกจากนี้ยังทำให้การดำเนินการนี้เป็นเรื่องง่ายสำหรับผู้ใช้ตั้งแต่ การเลิกทำสามารถเก็บสำเนารายการเก่าที่ราคาไม่แพงได้
ข้อยกเว้นความปลอดภัยหรือการกู้คืนข้อผิดพลาด
ทุกคนไม่ได้รับประโยชน์มากเท่ากับที่ฉันทำจากโครงสร้างข้อมูลถาวรในบริบทเช่นนี้ (ฉันพบว่ามีประโยชน์อย่างมากสำหรับพวกเขาในระบบเลิกทำและการแก้ไขแบบไม่ทำลายซึ่งเป็นแนวคิดหลักในโดเมน VFX ของฉัน) แต่สิ่งหนึ่ง ทุกคนที่ต้องพิจารณาคือข้อยกเว้นด้านความปลอดภัยหรือการกู้คืนข้อผิดพลาดข้อผิดพลาดในการกู้คืน
หากคุณต้องการทำให้ฟังก์ชั่นการกลายพันธุ์เป็นข้อยกเว้นที่ปลอดภัยแล้วมันต้องใช้ตรรกะการย้อนกลับซึ่งการดำเนินการที่ง่ายที่สุดนั้นต้องมีการคัดลอกรายการทั้งหมด :
void transform_stuff(MutList<Stuff>& stuff, int first, int last)
{
// Make a copy of the whole massive gigabyte-sized list
// in case we encounter an exception and need to rollback
// changes.
MutList<Stuff> old_stuff = stuff;
try
{
// Transform stuff in the range, [first, last).
for (; first != last; ++first)
transform(stuff[first]);
}
catch (...)
{
// If the operation failed and ran into an exception,
// swap the original list with the one we modified
// to "undo" our changes.
stuff.swap(old_stuff);
throw;
}
}
ณ จุดนี้เวอร์ชันที่ยกเว้นความปลอดภัยจะมีราคาสูงกว่าการคำนวณและเนื้อหาที่ยากต่อการเขียนอย่างถูกต้องกว่าเวอร์ชั่นที่ไม่เปลี่ยนรูปโดยใช้ "ผู้สร้าง" และนักพัฒนา C ++ หลายคนละเลยข้อยกเว้นด้านความปลอดภัยและอาจเป็นเรื่องดีสำหรับโดเมนของพวกเขา แต่ในกรณีของฉันฉันต้องการให้แน่ใจว่าโค้ดของฉันทำงานอย่างถูกต้องแม้ในกรณีที่มีข้อยกเว้น (แม้แต่เขียนการทดสอบที่จงใจโยนข้อยกเว้นเพื่อทดสอบข้อยกเว้น ความปลอดภัย) และนั่นทำให้ฉันต้องสามารถย้อนกลับผลข้างเคียงใด ๆ ฟังก์ชั่นทำให้เกิดครึ่งทางในการทำงานถ้ามีอะไรเกิดขึ้น
เมื่อคุณต้องการที่จะเป็นข้อยกเว้นที่ปลอดภัยและกู้คืนจากข้อผิดพลาดได้อย่างงดงามโดยที่แอปพลิเคชันของคุณหยุดทำงานและเบิร์นคุณต้องเปลี่ยน / เลิกทำผลข้างเคียงใด ๆ ที่ฟังก์ชันสามารถทำให้เกิดขึ้นได้ในกรณีที่เกิดข้อผิดพลาด / ข้อยกเว้น และที่นั่นผู้สร้างสามารถประหยัดเวลาโปรแกรมเมอร์ได้มากกว่าค่าใช้จ่ายพร้อมกับเวลาในการคำนวณเพราะ: ...
คุณไม่ต้องกังวลกับการย้อนกลับของผลข้างเคียงในฟังก์ชั่นที่ไม่ทำให้เกิดปัญหาใด ๆ !
ดังนั้นกลับไปที่คำถามพื้นฐาน:
ชั้นเรียนที่ไม่เปลี่ยนแปลงกลายเป็นภาระในจุดใด?
พวกเขามักจะเป็นภาระในภาษาที่หมุนรอบความไม่แน่นอนได้มากกว่าการไม่เปลี่ยนรูปซึ่งเป็นเหตุผลที่ฉันคิดว่าคุณควรใช้พวกเขาในกรณีที่ผลประโยชน์มีค่ามากกว่าค่าใช้จ่าย แต่ในระดับกว้างพอสำหรับโครงสร้างข้อมูลที่มีขนาดใหญ่พอฉันเชื่อว่ามีหลายกรณีที่เป็นการแลกเปลี่ยนที่คุ้มค่า
นอกจากนี้ในเหมืองฉันมีประเภทข้อมูลที่ไม่เปลี่ยนรูปแบบเพียงไม่กี่ชนิดและโครงสร้างข้อมูลขนาดใหญ่ทั้งหมดมีจุดประสงค์เพื่อจัดเก็บองค์ประกอบจำนวนมาก (พิกเซลของภาพ / พื้นผิวหน่วยงานและส่วนประกอบของ ECS และจุดยอด / ขอบ / รูปหลายเหลี่ยมของ ตาข่าย)