Saya awalnya memposting ini sebagai pertanyaan hanya tentang destruktor, tapi sekarang saya menambahkan pertimbangan konstruktor default. Inilah pertanyaan aslinya:
Jika saya ingin memberi kelas saya destruktor yang virtual, tetapi sebaliknya sama dengan apa yang akan dihasilkan oleh kompiler, saya dapat menggunakan
=default
:class Widget { public: virtual ~Widget() = default; };
Tapi sepertinya saya bisa mendapatkan efek yang sama dengan kurang mengetik menggunakan definisi kosong:
class Widget { public: virtual ~Widget() {} };
Apakah ada cara di mana kedua definisi ini berperilaku berbeda?
Berdasarkan balasan yang diposting untuk pertanyaan ini, situasi untuk konstruktor default tampak serupa. Mengingat hampir tidak ada perbedaan makna antara " =default
" dan " {}
" untuk destruktor, apakah hampir sama tidak ada perbedaan makna antara opsi-opsi ini untuk konstruktor default? Yaitu, dengan anggapan saya ingin membuat jenis di mana objek jenis itu akan dibuat dan dihancurkan, mengapa saya ingin mengatakan
Widget() = default;
dari pada
Widget() {}
?
Saya minta maaf jika memperpanjang pertanyaan ini setelah posting aslinya melanggar beberapa aturan SO. Posting pertanyaan yang hampir identik untuk konstruktor default mengejutkan saya sebagai pilihan yang kurang diinginkan.
sumber
= default
lebih eksplisit, dan konsisten dengan dukungan untuk itu dengan konstruktor.std::has_trivial_destructor<Widget>::value
jugatrue
untuk yang pertama, tetapifalse
untuk yang kedua. Apa implikasinya itu, saya juga tidak tahu. :)Jawaban:
Ini adalah pertanyaan yang sama sekali berbeda ketika bertanya tentang konstruktor daripada destruktor.
Jika destruktor Anda
virtual
, maka perbedaannya dapat diabaikan, seperti yang ditunjukkan Howard . Namun, jika destruktor Anda non-virtual , itu cerita yang sama sekali berbeda. Hal yang sama berlaku untuk konstruktor.Menggunakan
= default
sintaks untuk fungsi anggota khusus (konstruktor default, menyalin / memindahkan konstruktor / tugas, destruktor dll) berarti sesuatu yang sangat berbeda dari hanya melakukan{}
. Dengan yang terakhir, fungsi menjadi "yang disediakan pengguna". Dan itu mengubah segalanya.Ini adalah kelas sepele menurut definisi C ++ 11:
Jika Anda mencoba untuk membangunnya secara default, kompiler akan membuat konstruktor default secara otomatis. Hal yang sama berlaku untuk menyalin / memindahkan dan merusak. Karena pengguna tidak menyediakan fungsi-fungsi anggota ini, spesifikasi C ++ 11 menganggap ini sebagai kelas "sepele". Oleh karena itu sah untuk melakukan ini, seperti memcpy isinya sekitar untuk menginisialisasi mereka dan sebagainya.
Ini:
Seperti namanya, ini tidak lagi sepele. Ini memiliki konstruktor default yang disediakan pengguna. Tidak masalah jika itu kosong; sejauh menyangkut aturan C ++ 11, ini bukan tipe yang sepele.
Ini:
Sekali lagi seperti namanya, ini adalah jenis yang sepele. Mengapa? Karena Anda mengatakan kepada kompiler untuk secara otomatis menghasilkan konstruktor default. Karena itu konstruktor tidak "disediakan pengguna." Dan oleh karena itu, jenisnya dianggap sepele, karena tidak memiliki konstruktor default yang disediakan pengguna.
The
= default
sintaks terutama ada untuk melakukan hal-hal seperti konstruktor copy / tugas, ketika Anda menambahkan fungsi anggota yang mencegah penciptaan fungsi tersebut. Tapi itu juga memicu perilaku khusus dari kompiler, jadi itu berguna dalam konstruktor default / destruktor juga.sumber
=default
fungsi) dan fungsi yang disediakan pengguna (yang merupakan kasus untuk{}
). Fungsi yang dideklarasikan oleh pengguna dan yang disediakan pengguna dapat mencegah pembuatan fungsi anggota khusus lainnya (misalnya, destruktor yang dideklarasikan pengguna mencegah pembuatan operasi pemindahan), tetapi hanya fungsi khusus yang disediakan pengguna yang membuat kelas menjadi non-sepele. Baik?= default
tampaknya berguna untuk memaksa kompiler untuk menghasilkan konstruktor default meskipun ada konstruktor lain; konstruktor default tidak dinyatakan secara implisit jika ada konstruktor yang dideklarasikan pengguna lain disediakan.Keduanya non-sepele.
Mereka berdua memiliki spesifikasi noexcept yang sama tergantung pada spesifikasi noexcept dari pangkalan dan anggota.
Satu-satunya perbedaan yang saya deteksi sejauh ini adalah jika
Widget
mengandung basis atau anggota dengan destruktor yang tidak dapat diakses atau dihapus:Maka
=default
solusinya akan dikompilasi, tetapiWidget
tidak akan menjadi tipe yang dapat dirusak. Yaitu jika Anda mencoba untuk merusakWidget
, Anda akan mendapatkan kesalahan waktu kompilasi. Tetapi jika tidak, Anda punya program kerja.Otoh, jika Anda memasok destruktor yang disediakan pengguna , maka hal-hal tidak akan mengkompilasi apakah Anda merusak
Widget
:sumber
=default;
kompiler tidak akan menghasilkan destruktor kecuali jika digunakan, dan karenanya tidak akan memicu kesalahan. Ini tampak aneh bagi saya, bahkan jika belum tentu bug. Saya tidak bisa membayangkan perilaku ini diamanatkan dalam standar.Perbedaan penting antara
dan
adalah bahwa konstruktor default yang didefinisikan dengan
B() = default;
dianggap tidak didefinisikan pengguna . Ini berarti bahwa dalam hal inisialisasi nilai seperti padainisialisasi khusus yang tidak menggunakan konstruktor sama sekali akan terjadi dan untuk tipe bawaan ini akan menghasilkan inisialisasi nol . Dalam hal
B(){}
ini tidak akan terjadi. Standar C ++ n3337 § 8.5 / 7 mengatakanSebagai contoh:
hasil yang mungkin:
http://ideone.com/k8mBrd
sumber