ทำไมการใช้ std :: auto_ptr <> กับคอนเทนเนอร์มาตรฐานจึงผิด


217

ทำไมการใช้std::auto_ptr<>กับคอนเทนเนอร์มาตรฐานจึงผิด


5
+1 นี้แน่นอนเพราะฉันเห็นผู้คนจำนวนมากเข้าใจผิด มันเป็นคำถามที่ดีที่จะถาม
twokats

โปรดอ่านรายการที่เกี่ยวข้องด้วย คำถามนี้ถูกพิจารณาที่นี่จากอีกด้านหนึ่ง อาจเป็นประโยชน์ในการทำความเข้าใจเพิ่มเติมเกี่ยวกับ auto_ptr และคอนเทนเนอร์ STL stackoverflow.com/questions/8630552/…
nickolay


1
moveความหมายและถูกออกแบบมาเพื่อหลีกเลี่ยงปัญหาที่เกี่ยวข้องกับunique_ptr auto_ptrใน C ++ 03 ภาษาไม่ทรงพลังพอที่จะเขียนคลาสเช่นauto_ptrนั้นทำงานอย่างถูกต้องและปลอดภัยในทุกสถานการณ์เนื่องจากคอมไพเลอร์และภาษาไม่สามารถแยกความแตกต่างของค่า l และ r ดังนั้นจึงใช้ "hacks" บางอย่างเพื่อรับพฤติกรรมที่ต้องการ เวลาส่วนใหญ่.
Phil1970

บทความที่ดี: STL Containers และ Auto_ptrs - ทำไมพวกเขาไม่ผสมquantstart.com/articles/…
alfC

คำตอบ:


124

มาตรฐาน C ++ บอกว่าองค์ประกอบ STL จะต้อง "สามารถคัดลอกได้" และ "กำหนดได้" กล่าวอีกนัยหนึ่งองค์ประกอบจะต้องสามารถกำหนดหรือคัดลอกและองค์ประกอบทั้งสองนั้นเป็นอิสระตามหลักเหตุผล std::auto_ptrไม่ปฏิบัติตามข้อกำหนดนี้

ยกตัวอย่างรหัสนี้:

class X
{
};

std::vector<std::auto_ptr<X> > vecX;
vecX.push_back(new X);

std::auto_ptr<X> pX = vecX[0];  // vecX[0] is assigned NULL.

หากต้องการเอาชนะข้อ จำกัด นี้คุณควรใช้พอยstd::unique_ptrน์เตอร์std::shared_ptrหรือstd::weak_ptrสมาร์ทพอยน์เตอร์หรือการเพิ่มประสิทธิภาพเทียบเท่าหากคุณไม่มี C ++ 11 นี่คือเอกสารคู่มือการเพิ่มไลบรารีสำหรับพอยน์เตอร์อัจฉริยะเหล่านี้


7
คุณควรพิจารณาตัวชี้การเพิ่มตู้ถ้าคุณไม่ต้องการเป็นเจ้าของร่วม
me22

4
unique_ptrไม่อนุญาตให้คัดลอกดังนั้นการดำเนินการ STL บางอย่างจะไม่ทำงานอย่างถูกต้องเว้นแต่ว่าพวกเขาจะสามารถใช้ซีแมนทิกส์การย้าย
Mike Weller

4
"เพื่อเอาชนะข้อ จำกัด นี้คุณควรใช้std::unique_ptr": เทมเพลตของคลาสนั้นสามารถมีอยู่ได้เนื่องจากความหมายของการย้ายเท่านั้น (ข้อมูลจำเพาะของมันต้องการการอ้างอิง rvalue) ดังนั้นจึงจำเป็นต้องใช้ C ++ 11 โดยพื้นฐาน อย่างไรก็ตาม (และที่เกี่ยวข้อง) มาตรฐาน C ++ 11 ไม่ได้บอกว่าประเภทองค์ประกอบ STL ต้องเป็น "copy-constructible" และ "assignable"; ความพอเพียงที่สามารถเคลื่อนย้ายได้และสามารถกำหนดได้ แน่นอนว่าunique_ptrอินสแตนซ์นั้นสามารถเคลื่อนย้ายได้และสามารถกำหนดได้เท่านั้น แต่เป็นauto_ptrกรณี! เป็นผลให้ใน C ++ 11 คุณอาจจะทำอย่างไรกับสิ่งที่คุณสามารถทำอะไรกับauto_ptr unique_ptr
Marc van Leeuwen

@MarcvanLeeuwen ยกเว้นคุณresetและคนreleaseที่จำเป็น
ratchet freak

2
@ ratchetfreak: อืมฉันไม่เข้าใจ อะไร? "นอกจากคุณresetและrelease" ฉันไม่เห็นว่าจะมีผลกับสิ่งใดในความคิดเห็นของฉัน โปรดทราบว่าทั้งสองauto_ptrและunique_ptrมีทั้งสองวิธีนี้และพวกเขาทำสิ่งเดียวกันทั้งสองกรณี
Marc van Leeuwen

66

หมายสำเนาของauto_ptrไม่ได้เข้ากันได้กับภาชนะบรรจุ

การคัดลอกauto_ptrวัตถุหนึ่งไปยังอีกวัตถุหนึ่งนั้นไม่ได้สร้างวัตถุที่เท่ากันสองตัวเนื่องจากวัตถุหนึ่งสูญเสียความเป็นเจ้าของตัวชี้ไปแล้ว

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


39

สองบทความที่ยอดเยี่ยมที่สุดในเรื่อง:


เพราะฉันคิดว่าในการแทรกแซงเกือบสองปีเขาอาจจัดการกับปัญหาในมือ
ลูกสุนัข

27
@DeadMG: ใช่คุณถูกต้อง แต่นั่นไม่ใช่จุดประสงค์ของฉัน หากมีคนเข้ามาที่หัวข้อนี้ในบางครั้งและต้องการที่จะเรียนรู้auto_ptrและสิ่งต่าง ๆ ลิงค์เหล่านี้จะเป็นประโยชน์ฉันแน่ใจ
Lazer

มีหลายรายการที่ซ้ำกันที่ใหม่กว่า
ลูกสุนัข

8
@DeadMG: คำถามนี้ไม่ได้ปิดเหมือนซ้ำดังนั้นจึงเปิดสำหรับการขยาย Lazer พูดในสิ่งที่ไม่เคยพูดมาก่อน ฉันเดาว่าเขามาโดยบังเอิญ
Sebastian Mach

คำอธิบายในลิงค์ที่สองซึ่งวิเคราะห์ปัญหาหลังจากโทรsort()ได้ชัดเจนกว่าคำตอบทั้งหมดที่นี่
chaosink

17

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

มีคำอธิบายโดยละเอียดเกี่ยวกับสิ่งที่ผิดพลาดในรายการ STL (Scott Meyers) ที่มีผลบังคับใช้ 8 และคำอธิบายที่ไม่ละเอียดในรายการ C ++ ที่มีประสิทธิภาพ (Scott Meyers) รายการที่ 13


12

คอนเทนเนอร์ STL เก็บสำเนาของรายการที่มีอยู่ เมื่อคัดลอก auto_ptr มันจะตั้งค่า PTR เก่าให้เป็นโมฆะ วิธีการคอนเทนเนอร์จำนวนมากจะใช้งานไม่ได้โดยพฤติกรรมนี้


แต่เมื่อใช้ unique_ptr คุณจะได้สิ่งเดียวกันเพราะมีเพียงหนึ่งอันที่ไม่ซ้ำกันเท่านั้นที่สามารถมีกรรมสิทธิ์ของวัตถุได้
ผู้ติดตาม

2
@ Tracer unique_ptrเหมือนกับวัตถุ C ++ 11 ที่เหมาะสมเท่านั้นที่สามารถถ่ายโอนความเป็นเจ้าของทรัพยากรได้เมื่อมีการสร้างหรือย้ายที่ได้รับมอบหมายเพื่อให้มั่นใจว่าโปรแกรมเมอร์ต้องจงใจส่งผ่านstd::move(sourceObject)หรือชั่วคราวแทนที่จะส่งผ่านค่าlvalueและไม่ได้ตั้งใจ / ไม่คาดคิด สำเนามอบหมาย ... auto_ptrซึ่งเน้นเป็นไปอย่างทั่วถึงนี่เป็นปัญหาหลักของ
underscore_d

4

C ++ 03 Standard (ISO-IEC 14882-2003)พูดในข้อ 20.4.5 วรรค 3:

[... ] [ หมายเหตุ: [... ] auto_ptr ไม่เป็นไปตามข้อกำหนดของ CopyConstructible และ Assignable สำหรับองค์ประกอบคอนเทนเนอร์ไลบรารีมาตรฐานและทำให้อินสแตนซ์คอนเทนเนอร์คอนเทนเนอร์ไลบรารีมาตรฐานมีผลให้ auto_ptr มีพฤติกรรมที่ไม่ได้กำหนด - บันทึกท้าย ]

C ++ 11 มาตรฐาน (ISO-IEC 14882-2011)กล่าวในภาคผนวก D.10.1 วรรค 3:

[... ] หมายเหตุ: [... ] อินสแตนซ์ของ auto_ptr ตรงตามข้อกำหนดของ MoveConstructible และ MoveAssignable แต่ไม่ตรงตามข้อกำหนดของ CopyConstructible และ CopyAssignable - บันทึกท้าย]

C ++ 14 Standard (ISO-IEC 14882-2014)กล่าวไว้ในภาคผนวก C.4.2 ภาคผนวก D: คุณสมบัติความเข้ากันได้:

เปลี่ยนแปลง : เท็มเพลตคลาส auto_ptr, unary_function และ binary_function, เท็มเพลตฟังก์ชัน random_shuffle และเท็มเพลตฟังก์ชั่น (และประเภทที่ส่งคืน) ptr_fun, mem_fun, mem_fun_ref, bind1st และ bind2nd
เหตุผล : ถูกแทนที่ด้วยคุณสมบัติใหม่
ผลกระทบต่อคุณสมบัติดั้งเดิม : รหัส C ++ 2014 ที่ถูกต้องที่ใช้แม่แบบคลาสเหล่านี้และแม่แบบฟังก์ชันอาจไม่สามารถรวบรวมในมาตรฐานสากลนี้ได้

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