เงื่อนไขสำหรับการสร้าง ctor เริ่มต้น / คัดลอก / ย้ายอัตโนมัติและตัวดำเนินการกำหนดสำเนา / ย้าย?


127

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

ฉันจำได้ว่ามีกฎบางอย่าง แต่ฉันจำไม่ได้และยังไม่พบแหล่งข้อมูลที่มีชื่อเสียงทางออนไลน์ ใครสามารถช่วย?

คำตอบ:


136

ต่อไปนี้ "สร้างอัตโนมัติ" หมายถึง "ประกาศโดยปริยายว่าเป็นค่าเริ่มต้น แต่ไม่ได้กำหนดให้เป็นลบ" มีสถานการณ์ที่ประกาศฟังก์ชันสมาชิกพิเศษ แต่กำหนดเป็นลบ

  • ตัวสร้างเริ่มต้นถูกสร้างขึ้นโดยอัตโนมัติหากไม่มีตัวสร้างที่ผู้ใช้ประกาศ (§12.1 / 5)
  • ตัวสร้างการคัดลอกจะถูกสร้างขึ้นโดยอัตโนมัติหากไม่มีตัวสร้างการย้ายที่ผู้ใช้ประกาศหรือตัวดำเนินการกำหนดย้าย (เนื่องจากไม่มีตัวสร้างการย้ายหรือตัวดำเนินการกำหนดย้ายใน C ++ 03 สิ่งนี้จะทำให้ "เสมอ" ใน C ++ 03 ง่ายขึ้น) ( §12.8 / 8)
  • ตัวดำเนินการกำหนดสำเนาจะถูกสร้างขึ้นโดยอัตโนมัติหากไม่มีตัวสร้างการย้ายที่ผู้ใช้ประกาศหรือตัวดำเนินการกำหนดย้าย (§12.8 / 19)
  • ตัวทำลายจะสร้างขึ้นโดยอัตโนมัติหากไม่มีตัวทำลายที่ผู้ใช้ประกาศ (§12.4 / 4)

C ++ 11 และใหม่กว่าเท่านั้น:

  • ตัวสร้างการย้ายจะถูกสร้างขึ้นโดยอัตโนมัติหากไม่มีตัวสร้างการคัดลอกที่ผู้ใช้ประกาศตัวดำเนินการกำหนดสำเนาหรือตัวทำลายและถ้าตัวสร้างการย้ายที่สร้างนั้นถูกต้อง (§12.8 / 10)
  • ตัวดำเนินการกำหนดการย้ายจะสร้างขึ้นโดยอัตโนมัติหากไม่มีตัวสร้างการคัดลอกที่ผู้ใช้ประกาศตัวดำเนินการกำหนดสำเนาหรือตัวทำลายและถ้าตัวดำเนินการกำหนดย้ายที่สร้างขึ้นนั้นถูกต้อง (เช่นหากไม่จำเป็นต้องกำหนดสมาชิกคงที่) (§12.8 / 21)

9
Destructor ที่สืบทอดมานับหรือไม่? ฉันหมายความว่าฉันมีคลาสพื้นฐานที่มีตัวทำลายเสมือนที่ว่างเปล่า มันป้องกันการสร้างตัวสร้างการย้ายในคลาสย่อยหรือไม่? ถ้าคำตอบคือใช่จะช่วยได้หรือไม่ถ้าฉันกำหนดตัวสร้างการย้ายในคลาสฐาน
kamilk

10
ฉันคิดว่าคุณควรพูดถึงบางทีการมีconstสมาชิกในชั้นเรียนจะป้องกันไม่ให้ตัวสร้างสร้างขึ้นโดยอัตโนมัติ ...
nonsensickle

"มีสถานการณ์ที่มีการประกาศฟังก์ชันสมาชิกพิเศษ แต่ถูกกำหนดให้เป็นลบ" อ้างถึงที่ที่คุณมี const หรือสมาชิกอ้างอิงที่ย้ายจะเป็นไปไม่ได้? ไม่ได้เพราะจะมีการใช้สำเนา
towi

ฉันรู้ว่าการส่งไฮเปอร์ลิงก์ในฟอรัมนี้ถูก จำกัด แต่ก็เป็นบทความที่ดีเช่นกัน - cplusplus.com/articles/y8hv0pDG
bruziuz

โปรดทราบว่าตามมาตรฐานแล้วตัวสร้างการคัดลอกเริ่มต้นโดยปริยาย " จะเลิกใช้งานหากคลาสมีตัวดำเนินการกำหนดสำเนาที่ผู้ใช้ประกาศหรือผู้ทำลายที่ผู้ใช้ประกาศ " ( 12.8 การคัดลอกและย้ายอ็อบเจ็กต์คลาส [class.copy] )
sigy

98

ฉันพบว่าแผนภาพด้านล่างมีประโยชน์มาก

กฎ C ++ สำหรับตัวสร้างอัตโนมัติและตัวดำเนินการกำหนด จากSticky Bits - กลายเป็น Rule of Zero Hero


สวย. "อิสระ" หมายถึงอะไร? เป็นอิสระจากอะไร?
towi

8
คัดลอก ctor / การกำหนดเป็น 'อิสระ' จากกัน หากคุณเขียนเพียงหนึ่งคอมไพเลอร์จะจัดเตรียมอีกอัน ในทางตรงกันข้ามถ้าคุณระบุ ctor การย้ายหรือการมอบหมายการย้ายคอมไพเลอร์จะไม่จัดหาอื่น ๆ
Marco M.

สงสัยว่าอะไรคือเหตุผลเบื้องหลังการดำเนินการคัดลอกจึงเป็นอิสระ เหตุผลทางประวัติศาสตร์อาจเป็น? หรือความจริงที่ว่าสำเนาจะไม่แก้ไขเป้าหมาย แต่ย้ายได้อย่างไร
RaGa__M

@Explorer_N ใช่ความเข้ากันได้ย้อนหลังดังนั้นเหตุผลทางประวัติศาสตร์ เป็นตัวเลือกการออกแบบที่ไม่ดีเมื่อนานมาแล้วดังนั้นตอนนี้จึงจำเป็นต้องมีแนวทางปฏิบัติที่ดีเช่น "กฎสาม" (กำหนดทั้ง 3 หรือไม่มีเลย: ตัวสร้างการคัดลอกตัวดำเนินการกำหนดสำเนาและมักจะทำลาย) เพื่อหลีกเลี่ยงข้อบกพร่องที่ยากต่อการค้นหา
atablash

@MarcoM. เท่าที่ฉันเข้าใจเงื่อนไข "ถ้าคุณเขียน ... " รวมถึงสองกรณีของการตั้งค่าฟังก์ชันสมาชิกพิเศษเป็น= delete(ชัดเจน) หรือ= default(ไม่ชัดเจนสำหรับฉัน) ฉันถูกไหม?
Enrico Maria De Angelis

2

C ++ 17 N4659 ร่างมาตรฐาน

สำหรับการอ้างอิงข้ามมาตรฐานอย่างรวดเร็วโปรดดูที่ส่วน "ประกาศโดยนัย" ของรายการ cppreference ต่อไปนี้:

ข้อมูลเดียวกันนี้สามารถหาได้จากมาตรฐานแน่นอน เช่นในC ++ 17 N4659 ร่างมาตรฐาน :

15.8.1 "Copy / move constructor" สำหรับสำหรับ copy constructor:

6 ถ้านิยามคลาสไม่ได้ประกาศตัวสร้างการคัดลอกอย่างชัดเจนตัวสร้างที่ไม่ชัดเจนจะถูกประกาศโดยปริยาย ถ้านิยามคลาสประกาศตัวสร้างการย้ายหรือตัวดำเนินการกำหนดย้ายตัวสร้างการคัดลอกที่ประกาศโดยปริยายจะถูกกำหนดเป็นลบ มิฉะนั้นจะกำหนดเป็นค่าเริ่มต้น (11.4) กรณีหลังจะเลิกใช้ถ้าคลาสมีตัวดำเนินการกำหนดสำเนาที่ผู้ใช้ประกาศหรือตัวทำลายที่ผู้ใช้ประกาศ

และสำหรับตัวสร้างการย้าย:

8 ถ้านิยามของคลาส X ไม่ได้ประกาศตัวสร้างการย้ายอย่างชัดเจนตัวสร้างที่ไม่ชัดเจนจะถูกประกาศโดยปริยายว่าเป็นค่าเริ่มต้นถ้าและต่อเมื่อ

  • (8.1) - X ไม่มีตัวสร้างการคัดลอกที่ผู้ใช้ประกาศ

  • (8.2) - X ไม่มีตัวดำเนินการกำหนดสำเนาที่ผู้ใช้ประกาศ

  • (8.3) - X ไม่มีตัวดำเนินการกำหนดการย้ายที่ผู้ใช้ประกาศและ

  • (8.4) - X ไม่มีตัวทำลายที่ผู้ใช้ประกาศ

15.8.2 "ตัวดำเนินการกำหนดสำเนา / ย้าย" พูดสำหรับการกำหนดสำเนา:

2 ถ้านิยามคลาสไม่ได้ประกาศตัวดำเนินการกำหนดสำเนาอย่างชัดเจนตัวดำเนินการหนึ่งจะถูกประกาศโดยปริยาย ถ้านิยามคลาสประกาศตัวสร้างการย้ายหรือตัวดำเนินการกำหนดย้ายตัวดำเนินการกำหนดสำเนาที่ประกาศโดยปริยายจะถูกกำหนดเป็นลบ มิฉะนั้นจะกำหนดเป็นค่าเริ่มต้น (11.4) กรณีหลังจะเลิกใช้ถ้าคลาสมีตัวสร้างการคัดลอกที่ผู้ใช้ประกาศหรือตัวทำลายที่ผู้ใช้ประกาศ

และสำหรับการมอบหมายการย้าย:

4 ถ้านิยามของคลาส X ไม่ได้ประกาศตัวดำเนินการกำหนดการย้ายอย่างชัดเจนตัวดำเนินการหนึ่งจะถูกประกาศโดยปริยายว่าเป็นค่าเริ่มต้นถ้าและต่อเมื่อ

  • (4.1) - X ไม่มีตัวสร้างสำเนาที่ผู้ใช้ประกาศ
  • (4.2) - X ไม่มีตัวสร้างการย้ายที่ผู้ใช้ประกาศ
  • (4.3) - X ไม่มีตัวดำเนินการกำหนดสำเนาที่ผู้ใช้ประกาศและ
  • (4.4) - X ไม่มีตัวทำลายที่ผู้ใช้ประกาศ

15.4 "Destructors" กล่าวไว้สำหรับผู้ทำลาย:

4 ถ้าคลาสไม่มีตัวทำลายที่ผู้ใช้ประกาศตัวทำลายล้างจะถูกประกาศโดยปริยายว่าเป็นค่าเริ่มต้น (11.4) Destructor ที่ประกาศโดยปริยายเป็นสมาชิกสาธารณะแบบอินไลน์ของคลาส

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