ใช้พอยน์เตอร์ที่ไม่ใช่อัจฉริยะใน C ++ สมัยใหม่

เวอร์ชันสั้น:
มีเหตุผลใดที่ยอมรับได้ในการใช้พอยน์เตอร์ที่ไม่ใช่อัจฉริยะใน C++ สมัยใหม่หรือไม่

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

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


person MBZ    schedule 17.10.2013    source แหล่งที่มา
comment
ถ้าพวกเขาไม่ได้เป็นเจ้าของอะไรก็ไม่มีประโยชน์อะไรมาก   -  person chris    schedule 17.10.2013
comment
ปัญหาคือพวกเขาไม่ควรเป็นตัวชี้เลยตั้งแต่แรก (ตัวชี้แบบดิบไม่มีที่มากใน c ++ สมัยใหม่อย่างที่คุณพูด) แต่หากมันไม่เสียหายอย่าแก้ไข   -  person aaronman    schedule 17.10.2013
comment
ตัวชี้แบบดิบนั้นใช้ได้ใน c ++ สมัยใหม่หากพวกเขาไม่ได้เป็นเจ้าของทรัพยากรใด ๆ นั่นหมายความว่าคุณไม่จำเป็นต้องเปลี่ยนตัวชี้แบบดิบทั้งหมดให้เป็นตัวชี้แบบอัจฉริยะ   -  person StereoMatching    schedule 17.10.2013


คำตอบ (5)


พอยน์เตอร์อัจฉริยะ (unique_ptr และ shared_ptr) ควรเป็นตัวชี้ที่เป็นเจ้าของ (นั่นคือ รับผิดชอบในการทำลายวัตถุ) บรรทัดล่างของการใช้สิ่งเหล่านี้คือวัตถุใด ๆ ที่สร้างโดย new ควรถูกผลักเข้าไปใน unique_ptr ASAP เพื่อป้องกันการรั่วไหลของหน่วยความจำ หลังจากนั้น unique_ptr ควรจะถูกย้าย:

  • ลงใน shared_ptr หากควรแชร์ความเป็นเจ้าของ
  • หรือเข้าสู่ unique_ptr หากความเป็นเจ้าของถูกกำหนดโดยขอบเขต (ของบล็อกหรืออายุการใช้งานของวัตถุ)

releases น่าจะหายาก หากรหัสของคุณส่งพอยน์เตอร์ที่ไม่ใช่เจ้าของ สิ่งเหล่านี้ควรเป็น:

  • พอยน์เตอร์ดิบหากอาจเป็น null (ได้มาจาก get)
  • การอ้างอิงหากอาจไม่ใช่ null (ได้มาจาก get)
  • unique_ptrs ตามค่าหากเป้าหมายของการโทรคือการโอนความเป็นเจ้าของ (ซึ่งในกรณีนี้คุณจะต้องย้ายมัน)

วิธีการจากโรงงานควรส่งคืน unique_ptrs ตามค่า (เพราะว่าถ้าคุณไม่กำหนดค่าที่ส่งคืนของวิธีโรงงาน วัตถุจะยกเลิกการจัดสรรทันที)

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

person Laurent LA RIZZA    schedule 17.10.2013

เวอร์ชันสั้น:
มีเหตุผลใดที่ยอมรับได้ในการใช้พอยน์เตอร์ที่ไม่ใช่อัจฉริยะใน C++ สมัยใหม่หรือไม่

คำตอบสั้นๆ:

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

เวอร์ชันยาว:
เรามีผลิตภัณฑ์ขนาดใหญ่ที่มีโค้ด C++ เก่าจำนวนมาก และตอนนี้เรากำลังพยายามปรับโครงสร้างใหม่ให้เข้ากับยุค C++ สมัยใหม่ [...]

คำตอบยาว:

ขณะที่ฉันกำลังอ่านบรรทัดเหล่านี้ คำตอบนี้เข้ามาในใจ:

ฉันหวังว่าฉันจะโหวตคำตอบนี้มากกว่าหนึ่งครั้ง ฉันจะอ้างอิง: "[...] สำหรับแต่ละปัจจัยใหม่ที่เราได้ทำ เราสามารถพิสูจน์ได้ว่า 'การเปลี่ยนแปลงเฉพาะนี้จะทำให้งานจริงที่เรากำลังทำอยู่ตอนนี้ง่ายขึ้น' แทนที่จะเป็น 'ตอนนี้สะอาดขึ้นสำหรับงานในอนาคต '."

เรื่องสั้นอย่าทำการปรับโครงสร้างครั้งใหญ่เว้นแต่ว่าจำเป็นจริงๆ

คำถามก็คือ: มีการใช้พอยน์เตอร์อัจฉริยะมากเกินไปหรือไม่?

ในความคิดของฉัน std::shared_ptr ถูกใช้มากเกินไป ใช้งานได้สะดวกสบายมากและทำให้คุณรู้สึกเหมือนว่าคุณไม่จำเป็นต้องคิดถึงปัญหาในการเป็นเจ้าของ แต่นั่นไม่ใช่ภาพรวมทั้งหมด ฉันเห็นด้วยอย่างยิ่งกับ Sean Parent: "a shared pointer ดีพอๆ กับตัวแปรส่วนกลาง" ตัวชี้ที่ใช้ร่วมกันยังสามารถแนะนำปัญหาการเป็นเจ้าของที่ยากมาก ฯลฯ

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

คำพูดที่น่าสนใจจาก Sean Parent เกี่ยวกับวิธีหลีกเลี่ยง/ลดการใช้พอยน์เตอร์คือ:

หวังว่านี่จะช่วยได้

person Ali    schedule 17.10.2013

ใช่ ตัวชี้แบบดิบยังคงใช้เป็น "ข้อมูลอ้างอิงเพิ่มเติม" เช่น. a T* คล้ายกับ T& ไม่ได้หมายความถึงความเป็นเจ้าของ แต่ T* สามารถเป็น nullptr ได้

person MSalters    schedule 17.10.2013
comment
แต่แน่นอนว่ามีทางเลือกอื่นที่ปลอดภัยกว่าพอยน์เตอร์ดิบสำหรับสิ่งนี้ ฉันกำลังคิดถึงประเภท boost's (ตอนนี้ยังเป็น std::experimental's) optional เนื่องจากมีความชัดเจนว่าเกิดอะไรขึ้น แต่แม้แต่พอยน์เตอร์อัจฉริยะเองก็สามารถใช้ในลักษณะนี้ได้ - person JimmidyJoo; 02.05.2016
comment
@JimmidyJoo: ใช่ ฉันได้สร้างการสังเกตแบบเดียวกันทุกประการ เมื่อวาน - person MSalters; 02.05.2016

ดูการเสวนาได้ที่นี่: http://channel9.msdn.com/Events/GoingNative/2013 (โดยเฉพาะคำพูดของ Stroustrup)

คำตอบสั้นๆ คือไม่ สมมติว่า "modern C++" คือ >= c++11

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

person Dweeberly    schedule 17.10.2013
comment
เอิ่ม C++ สมัยใหม่คืออะไร ›= c++11 หมายถึงอะไร - person aaronman; 17.10.2013
comment
@aaronman สมมติว่าโดย 'modern C++' OP หมายถึง C++11 หรือใหม่กว่า - person Jonathan Potter; 17.10.2013
comment
ยังไม่มีข้อแก้ตัวในการเขียนโค้ดที่ไม่ถูกต้องใน C++03 - person R. Martinho Fernandes; 17.10.2013

แน่นอนว่ายังมีกรณีการใช้งานสำหรับพอยน์เตอร์ดิบใน C ++ สมัยใหม่:

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

แน่นอนว่ากรณีเหล่านี้ค่อนข้างหายาก และสำหรับกรณีการใช้งานส่วนใหญ่ของพอยน์เตอร์ พอยน์เตอร์อัจฉริยะน่าจะใช้ได้สำหรับโค้ดใหม่ แต่:

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

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

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

หากการปรับโครงสร้างใหม่จะช่วยประหยัดเวลาได้มากกว่าค่าใช้จ่ายสำหรับเพียงบางส่วนของฐานโค้ด ให้พิจารณาปรับโครงสร้างใหม่เฉพาะส่วนเหล่านั้นของฐานโค้ดเท่านั้น

person Kaiserludi    schedule 17.10.2013