การจัดการทรัพยากรที่ไม่ได้กำหนดไว้ว่าเป็นสิ่งที่เป็นนามธรรมหรือไม่?


9

จากสิ่งที่ฉันเห็นมีรูปแบบการจัดการทรัพยากรที่แพร่หลายอยู่สองรูปแบบคือการทำลายล้างที่กำหนดขึ้นและชัดเจน ตัวอย่างของอดีตจะเป็น destructors C ++ และตัวชี้สมาร์ทหรือย่อย DESTROY ของ Perl ในขณะที่ตัวอย่างหลังจะเป็นกระบวนทัศน์แบบบล็อกต่อการจัดการทรัพยากรของ Ruby หรืออินเทอร์เฟซ IDispose ของ. NET

ภาษาที่ใหม่กว่าดูเหมือนจะเลือกใช้ในภายหลังซึ่งอาจเป็นผลข้างเคียงของการใช้ระบบรวบรวมขยะที่หลากหลายที่ไม่อ้างอิงการนับ

คำถามของฉันคือ: เนื่องจาก destructors สำหรับสมาร์ทพอยน์เตอร์หรือระบบรวบรวมขยะอ้างอิง - เกือบจะเป็นสิ่งเดียวกัน - อนุญาตให้มีการทำลายทรัพยากรโดยปริยายและโปร่งใสมันเป็นสิ่งที่เป็นนามธรรมน้อยรั่วกว่าประเภทที่ไม่ได้กำหนดไว้ล่วงหน้า สัญกรณ์?

ฉันจะยกตัวอย่างที่เป็นรูปธรรม หากคุณมีคลาสย่อย C ++ สามคลาสของซูเปอร์คลาสเดียวอาจมีการใช้งานที่ไม่ต้องการการทำลายที่เฉพาะเจาะจง บางทีมันอาจใช้เวทมนตร์ในอีกทางหนึ่ง ความจริงที่ว่ามันไม่ต้องการการทำลายพิเศษใด ๆ นั้นไม่เกี่ยวข้อง - คลาสย่อยทั้งหมดยังคงใช้ในลักษณะเดียวกัน

ตัวอย่างอื่นใช้บล็อก Ruby คลาสย่อยสองคลาสจำเป็นต้องเพิ่มรีซอร์สดังนั้นคลาสคลาส opts สำหรับอินเตอร์เฟสที่ใช้บล็อกในตัวสร้างแม้ว่าคลาสย่อยย่อยอื่นอาจไม่ต้องการเนื่องจากมันไม่ต้องการการทำลายพิเศษ

เป็นกรณีที่การรั่วไหลหลังรายละเอียดการใช้งานของการทำลายทรัพยากรในขณะที่อดีตไม่ได้หรือไม่

แก้ไข: การเปรียบเทียบสมมติว่า Ruby กับ Perl อาจมีความยุติธรรมมากกว่าเนื่องจากมีการทำลายล้างที่กำหนดและที่เหลือไม่ได้ แต่พวกเขาทั้งคู่เก็บขยะ


5
ฉันอยากจะพูดว่า "ใช่" แต่ฉันชอบที่จะได้ยินสิ่งที่คนอื่นพูดเกี่ยวกับ
Bart van Ingen Schenau

การทำลายทรัพยากรโปร่งใส นอกจากความจริงที่ว่าคุณต้องใช้พอยน์เตอร์อัจฉริยะแทนพอยน์เตอร์ธรรมดา? ฉันไม่คิดว่านี่จะโปร่งใสกว่ามีเพียงกลไกเดียว (การอ้างอิง) เพื่อเข้าถึงวัตถุ (ใน C ++ คุณมีอย่างน้อยสี่หรือห้า)
Giorgio

@Giorgio: "วิธีการเข้าถึงวัตถุ" ค่อนข้างคลุมเครือ คุณหมายถึงอ่านหรือเขียน? คุณสมบัติ Const / ระเหย? พอยน์เตอร์ไม่ใช่ "วิธีเข้าถึงวัตถุ" จริงๆ การแสดงออกใด ๆ นั้นส่งผลให้เกิดวัตถุและการลดทอนตัวชี้ก็ไม่ได้พิเศษ
MSalters

1
@Giorgio: ในแง่ของ OOP นั้นคุณไม่สามารถส่งข้อความไปยังตัวชี้ C ++ ได้ คุณจำเป็นต้อง dereference ตัวชี้เพื่อส่งข้อความหรือเท่ากัน(*ptr).Message() ptr->Message()มีชุดของนิพจน์ที่อนุญาตไม่สิ้นสุดเช่นเดียวกับที่((*ptr))->Messageเทียบเท่า แต่พวกเขาทั้งหมดต้มลงไปexpressionIdentifyingAnObject.Message()
MSalters

1
ด้วย refcounting คุณต้องระมัดระวังเกี่ยวกับการหลีกเลี่ยงวงการ ดังนั้นสิ่งที่เป็นนามธรรมก็รั่วไหลเช่นกันในวิธีที่ต่างออกไป
CodesInChaos

คำตอบ:


2

ตัวอย่างของคุณตอบคำถาม การทำลายแบบโปร่งใสนั้นรั่วน้อยกว่าการทำลายอย่างชัดเจน มันสามารถรั่ว แต่รั่วน้อยกว่า

การทำลายอย่างชัดเจนนั้นคล้ายคลึงกับ malloc / free ใน C กับข้อผิดพลาดทั้งหมด อาจใช้น้ำตาลซินแทคติคเพื่อทำให้มันดูเป็นขอบเขต

ประโยชน์บางประการของการทำลายล้างอย่างชัดเจนเหนือ: -
รูปแบบการใช้งาน
เหมือนกัน - คุณไม่สามารถลืมที่จะปล่อยทรัพยากร
- ทำความสะอาดรายละเอียดอย่าทิ้งแนวนอน ณ จุดใช้งาน


2

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

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

ถ้าเช่นมีวิธีการในการสร้างวัตถุ "โปรแกรมระบายสี" ตัวนับใหม่ให้ดำเนินการบางอย่างกับตัวควบคุมสังเกตว่ามีการทาสีตัวควบคุมซ้ำกี่ครั้งแล้วละทิ้งวัตถุตัวนับสีวัตถุจะยังคงสมัครรับข้อมูลเหตุการณ์ แม้ว่าจะไม่มีใครสนใจถ้าวัตถุและการอ้างอิงทั้งหมดหายไปอย่างง่ายดาย อย่างไรก็ตามวัตถุจะไม่มีคุณสมบัติในการสะสมจนกว่าจะมีการควบคุม หากวิธีนั้นเป็นวิธีที่จะเรียกใช้หลายพันครั้งภายในอายุการใช้งานของตัวควบคุม [สถานการณ์ที่เป็นไปได้] มันอาจทำให้หน่วยความจำล้น แต่สำหรับข้อเท็จจริงที่ว่าค่าใช้จ่ายของการร้องขอ N อาจเป็น O (N ^ 2) หรือ O (N ^ 3) เว้นแต่การประมวลผลการสมัครสมาชิกจะมีประสิทธิภาพมากและการดำเนินการส่วนใหญ่ไม่ได้เกี่ยวข้องกับการวาดภาพใด ๆ

สถานการณ์นี้สามารถจัดการได้โดยให้การควบคุมเก็บการอ้างอิงที่อ่อนแอไปยังวัตถุตัวนับมากกว่าหนึ่งตัวที่แข็งแกร่ง รูปแบบการสมัครรับข้อมูลที่อ่อนแอมีประโยชน์ แต่ไม่ได้ผลในกรณีทั่วไป สมมติว่าแทนที่จะต้องการมีวัตถุที่ตรวจสอบเหตุการณ์ชนิดเดียวจากการควบคุมเดียวเราต้องการให้วัตถุ event-logger ที่ตรวจสอบการควบคุมหลายอย่างและกลไกการจัดการเหตุการณ์ของระบบนั้นแต่ละตัวควบคุมต้องการการอ้างอิง ไปยังวัตถุตัวบันทึกเหตุการณ์อื่น ในกรณีดังกล่าววัตถุที่เชื่อมโยงตัวควบคุมกับตัวบันทึกเหตุการณ์จะยังคงอยู่ตราบเท่าที่ทั้งสองการควบคุมที่ถูกตรวจสอบและตัวบันทึกเหตุการณ์ยังคงมีประโยชน์ หากทั้งตัวควบคุมและตัวบันทึกเหตุการณ์ไม่มีการอ้างอิงที่แข็งแกร่งถึงเหตุการณ์การเชื่อมโยงมันจะหยุดอยู่แม้ว่าจะยังมี "ประโยชน์" อยู่ก็ตาม หากทั้งสองมีเหตุการณ์ที่แข็งแกร่งอายุการใช้งานของวัตถุการเชื่อมโยงอาจขยายได้ไร้ประโยชน์แม้ว่าอีกคนหนึ่งตาย

หากไม่มีการอ้างอิงถึงวัตถุใด ๆ ในเอกภพวัตถุอาจถูกพิจารณาว่าไร้ประโยชน์และปลอดภัยจากการมีอยู่จริง ความจริงที่ว่าการอ้างอิงมีอยู่กับวัตถุอย่างไรก็ตามไม่ได้หมายความว่าวัตถุนั้น "มีประโยชน์" ในหลายกรณีประโยชน์ที่แท้จริงของวัตถุจะขึ้นอยู่กับการมีอยู่ของการอ้างอิงไปยังวัตถุอื่นซึ่งจากมุมมอง GC - ไม่เกี่ยวข้องกับพวกเขาทั้งหมด

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


0

ไม่มี "ตัวทำลายหรืออินเทอร์เฟซอื่น ๆ ที่ระบุว่า" คลาสนี้จะต้องถูกทำลาย "เป็นสัญญาของอินเทอร์เฟซนั้นถ้าคุณสร้าง subtype ที่ไม่ต้องการการทำลายแบบพิเศษ .

สำหรับซีพลัสพลัสกับคนอื่น ๆ นั้นไม่แตกต่างกันมากนัก C ++ บังคับให้ส่วนต่อประสานนั้นกับวัตถุทั้งหมดเป็นวัตถุ บทคัดย่อไม่สามารถรั่วไหลได้เมื่อพวกเขาต้องการภาษา


4
"หากคุณสร้างประเภทย่อยที่ไม่ต้องการการทำลายพิเศษ" นั่นไม่ใช่การละเมิด LSP เนื่องจากไม่มีการใช้งานเป็นกรณีพิเศษที่ถูกต้องในการทำลาย ปัญหาคือเมื่อคุณเพิ่มข้อกำหนดการทำลายให้กับคลาสที่ได้รับ
CodesInChaos

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

@CodesInChaos - อ่าใช่ฉันคิดว่ามันเป็นเรื่องจริง
Telastyn

@ljackman: คลาสที่ต้องการการทำลายแบบพิเศษจะกำหนดภาระให้กับใครก็ตามที่เรียกตัวสร้างของมันเพื่อให้แน่ใจว่ามันจะถูกนำไปใช้ สิ่งนี้ไม่ได้สร้างการละเมิด LSP เนื่องจากDerivedFooThatRequiresSpecialDestructionสามารถสร้างได้ด้วยรหัสที่เรียกnew DerivedFooThatRequiresSpecialDestruction()เท่านั้น ในทางกลับกันวิธีการจากโรงงานซึ่งส่งคืนDerivedFooThatRequiresSpecialDestructionรหัสไปยังที่ไม่ได้คาดหวังสิ่งที่ต้องการการทำลายจะเป็นการละเมิด LSP
supercat

0

คำถามของฉันคือ: เนื่องจาก destructors สำหรับสมาร์ทพอยน์เตอร์หรือระบบรวบรวมขยะอ้างอิง - เกือบจะเป็นสิ่งเดียวกัน - อนุญาตให้มีการทำลายทรัพยากรโดยปริยายและโปร่งใสมันเป็นสิ่งที่เป็นนามธรรมน้อยรั่วกว่าประเภทที่ไม่ได้กำหนดไว้ล่วงหน้า สัญกรณ์?

ต้องคอยดูรอบด้วยมือไม่ว่าจะโดยปริยายหรือโปร่งใส ข้อยกเว้นเพียงอย่างเดียวคือระบบการนับการอ้างอิงด้วยภาษาที่ห้ามรอบโดยการออกแบบ Erlang อาจเป็นตัวอย่างของระบบดังกล่าว

ดังนั้นทั้งสองวิธีรั่วไหล ความแตกต่างที่สำคัญคือ destructors รั่วไหลทุกที่ใน C ++ แต่IDisposeหายากมากใน. NET


1
ยกเว้นวัฏจักรนั้นหายากเหลือเกินและไม่เกิดขึ้นจริงยกเว้นในโครงสร้างข้อมูลที่มีวัฏจักรอย่างชัดเจน ความแตกต่างที่สำคัญคือ destructors ใน C ++ ได้รับการจัดการอย่างถูกต้องทุกที่ แต่ IDispose ไม่ค่อยจัดการปัญหาใน. NET
DeadMG

"ยกเว้นวัฏจักรหายากเหลือเกิน" ในภาษาที่ทันสมัย? ฉันจะท้าทายสมมติฐานนั้น
Jon Harrop
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.