Kondisi untuk pembuatan otomatis operator salin default / salin / pindahkan dan salin / pindahkan?

127

Saya ingin menyegarkan ingatan saya pada kondisi di mana kompiler biasanya otomatis menghasilkan konstruktor default, menyalin konstruktor dan operator penugasan.

Saya ingat ada beberapa aturan, tetapi saya tidak ingat, dan juga tidak dapat menemukan sumber daya online yang memiliki reputasi baik. Adakah yang bisa membantu?

oompahloompah
sumber

Jawaban:

136

Berikut ini, "dihasilkan otomatis" berarti "secara implisit dinyatakan sebagai default, tetapi tidak didefinisikan sebagai dihapus". Ada situasi di mana fungsi anggota khusus dinyatakan, tetapi didefinisikan sebagai dihapus.

  • Konstruktor default dibuat secara otomatis jika tidak ada konstruktor yang dideklarasikan oleh pengguna (§12.1 / 5).
  • Salin konstruktor dihasilkan secara otomatis jika tidak ada konstruktor pemindahan yang dideklarasikan oleh pengguna atau operator penugasan pemindahan (karena tidak ada pemindah konstruktor atau operator penugasan pemindahan di C ++ 03, ini menyederhanakan menjadi "selalu" di C ++ 03) ( §12.8 / 8).
  • Operator penugasan salinan dibuat secara otomatis jika tidak ada konstruktor perpindahan yang dideklarasikan oleh pengguna atau operator penugasan pindah (§12.8 / 19).
  • Destuktor dibuat secara otomatis jika tidak ada destruktor yang dideklarasikan oleh pengguna (§12.4 / 4).

C ++ 11 dan yang lebih baru saja:

  • Konstruktor pemindahan dibuat secara otomatis jika tidak ada copy constructor yang dideklarasikan oleh pengguna, operator penugasan copy atau destruktor, dan jika konstruktor pemindahan yang dihasilkan valid (§12.8 / 10).
  • Operator penugasan langkah dibuat secara otomatis jika tidak ada copy constructor yang dideklarasikan oleh pengguna, operator penugasan salin atau destruktor, dan jika operator penugasan langkah yang dihasilkan valid (misalnya jika tidak perlu menetapkan anggota tetap) (§12.8 / 21).
Philipp
sumber
9
Apakah penghancur yang diturunkan diperhitungkan? Maksudku, katakan aku punya kelas dasar dengan destruktor virtual kosong. Apakah itu mencegah pembuatan konstruktor bergerak di subkelas? Jika jawabannya adalah ya, apakah akan membantu jika saya mendefinisikan move constructor di kelas dasar?
kamilk
10
Saya pikir Anda harus menyebutkan mungkin bahwa memiliki constanggota di kelas akan mencegah konstruktor dari yang dihasilkan secara otomatis ...
nonsensickle
Apakah "Ada situasi di mana fungsi anggota khusus dinyatakan, tetapi didefinisikan sebagai dihapus." lihat di mana Anda misalnya memiliki const atau anggota referensi di mana perpindahan tidak mungkin dilakukan? Tidak, itu tidak mungkin, karena salinan akan diterapkan.
towi
Saya tahu bahwa mengirim hyperlink di forum ini terbatas. Tapi ini juga artikel yang bagus - cplusplus.com/articles/y8hv0pDG
bruziuz
Catatan, bahwa sesuai standar, konstruktor salinan bawaan yang secara default " tidak digunakan lagi jika kelas memiliki operator penugasan salinan yang dideklarasikan pengguna atau destruktor yang dideklarasikan pengguna " ( 12.8 Menyalin dan memindahkan objek kelas [class.copy] ).
sigy
98

Saya menemukan diagram di bawah ini sangat bermanfaat.

Aturan C ++ untuk konstruktor dan operator penugasan otomatis dari Sticky Bits - Menjadi Aturan Nol Pahlawan

Marco M.
sumber
Cantik. Apa yang dimaksud "independen"? Bebas dari apa?
towi
8
Copy ctor / assignment bersifat 'independen' dari satu sama lain. Jika Anda hanya menulis satu, kompiler akan menyediakan yang lain. Sebaliknya, jika Anda memberikan pemindah langkah atau pemindahan tugas, kompiler tidak akan memasok yang lain.
Marco M.
Bertanya-tanya apa alasan di balik operasi penyalinan independen. Alasan bersejarah mungkin? atau fakta bahwa penyalinan tidak akan memodifikasi targetnya tetapi pemindahan tidak?
RaGa__M
@Explorer_N Ya, kompatibilitas, alasan historis. Itu adalah pilihan desain yang buruk sejak lama, jadi sekarang ada kebutuhan untuk praktik yang baik seperti "aturan tiga" (tentukan semua 3 atau tidak sama sekali: copy constructor, copy copy operator, dan sering destructor) untuk menghindari kesulitan menemukan bug.
atablash
@ MarscoM., Sejauh yang saya mengerti, kondisi "Jika Anda menulis ..." mencakup dua kasus pengaturan fungsi anggota khusus ke = delete(jelas) atau = default(kurang jelas bagi saya). Apakah saya benar?
Enrico Maria De Angelis
2

C ++ 17 N4659 konsep standar

Untuk referensi standar lintas cepat, lihat bagian "Dideklarasikan secara implisit" dari entri preferensi cppreferensi berikut:

Informasi yang sama tentu saja dapat diperoleh dari standar. Misalnya pada C ++ 17 N4659 draft standar :

15.8.1 "Salin / pindahkan konstruktor" kata untuk konstruktor salin:

6 Jika definisi kelas tidak secara eksplisit mendeklarasikan konstruktor salinan, definisi non-eksplisit dinyatakan secara implisit. Jika definisi kelas menyatakan move constructor atau move assignment operator, copy constructor yang dideklarasikan secara implisit didefinisikan sebagai dihapus; jika tidak, itu didefinisikan sebagai default (11.4). Kasus terakhir tidak digunakan lagi jika kelas memiliki operator penugasan salinan yang dideklarasikan pengguna atau destruktor yang dideklarasikan pengguna.

dan untuk move constructor:

8 Jika definisi kelas X tidak secara eksplisit menyatakan move constructor, definisi non-eksplisit akan secara implisit dinyatakan sebagai default jika dan hanya jika

  • (8.1) - X tidak memiliki konstruktor salin yang dinyatakan pengguna,

  • (8.2) - X tidak memiliki operator penugasan salinan yang dinyatakan pengguna,

  • (8.3) - X tidak memiliki operator penugasan pindah yang dinyatakan pengguna, dan

  • (8.4) - X tidak memiliki destruktor yang dinyatakan pengguna.

15.8.2 "Operator salin / pindahkan tugas" mengatakan untuk tugas salin:

2 Jika definisi kelas tidak secara eksplisit menyatakan operator penugasan salinan, satu dinyatakan secara implisit. Jika definisi kelas menyatakan move constructor atau operator penugasan pindah, operator penugasan salinan yang dinyatakan secara implisit didefinisikan sebagai dihapus; jika tidak, itu didefinisikan sebagai default (11.4). Kasus yang terakhir tidak digunakan lagi jika kelas memiliki konstruktor salinan yang dideklarasikan pengguna atau destruktor yang dideklarasikan pengguna.

dan untuk pemindahan tugas:

4 Jika definisi kelas X tidak secara eksplisit mendeklarasikan operator penugasan pindah, seseorang akan secara implisit dinyatakan sebagai default jika dan hanya jika

  • (4.1) - X tidak memiliki copy constructor yang dideklarasikan oleh pengguna,
  • (4.2) - X tidak memiliki konstruktor pemindahan yang dideklarasikan oleh pengguna,
  • (4.3) - X tidak memiliki operator penugasan salinan yang dinyatakan pengguna, dan
  • (4.4) - X tidak memiliki destruktor yang dideklarasikan pengguna.

15.4 "Destructors" mengatakannya untuk destructor:

4 Jika sebuah kelas tidak memiliki destruktor yang dideklarasikan pengguna, sebuah destruktor secara implisit dinyatakan sebagai default (11.4). Destroyer yang dideklarasikan secara implisit adalah anggota publik inline dari kelasnya.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber