mengapa secara eksplisit menghapus konstruktor?

95

Kapan / mengapa saya ingin menghapus konstruktor saya secara eksplisit? Dengan asumsi alasannya adalah untuk mencegah penggunaannya, mengapa tidak dibuat saja private?

class Foo
{ 
  public: 
    Foo() = delete; 
};
Abu
sumber
14
Ini berjalan baik dengan = default, bahkan kelas tidak dapat menggunakannya, dan saya pribadi lebih suka melihat Penggunaan fungsi yang dihapus. lebih dari Fungsi bersifat pribadi. Yang pertama secara eksplisit menyatakan "Ini tidak dimaksudkan untuk digunakan." Jika ada yang keluar dari itu, kelas tidak dapat menggunakannya sebenarnya membuat perbedaan semantik.
chris
16
Sejujurnya saya berpikir orang-orang mulai menjadi agresif dengan suara yang hampir habis. Saya tidak melihat bagaimana ini tidak konstruktif.
Luchian Grigore
4
@LuchianGrigore: Setuju. Saya bertanya-tanya mengapa komunitas saya sendiri menjadi jauh lebih kaku. Saya tidak mengerti maksudnya.
Ed S.
11
Karena saya jarang menggunakan C ++ 11, ini lebih informatif bagi saya daripada yang mungkin disadari oleh OP. Aku bahkan tidak tahu kamu bisa menandai konstruktor untuk delete. Baik pertanyaan maupun jawaban Luchian dengan mudah bisa dianggap konstruktif. Siapa pun yang tidak menghirup poin-poin penting dari C ++ 11 tetapi perlu segera akan mendapatkan sesuatu dari keduanya.
WhozCraig
Kemungkinan duplikat dari Apa gunanya menghapus konstruktor kelas default?
pengguna673679

Jawaban:

89

Bagaimana tentang:

//deleted constructor
class Foo
{ 
  public: 
    Foo() = delete;     
  public:
    static void foo();
};

void Foo::foo()
{
   Foo f;    //illegal
}

melawan

//private constructor
class Foo
{ 
  private: 
    Foo() {}     
  public:
    static void foo();
};

void Foo::foo()
{
   Foo f;    //legal
}

Mereka pada dasarnya berbeda. privatememberitahu Anda bahwa hanya anggota kelas yang dapat memanggil metode itu atau mengakses variabel itu (atau teman tentu saja). Dalam hal ini, sah untuk staticmetode kelas itu (atau anggota lain) untuk memanggil privatekonstruktor kelas. Ini tidak berlaku untuk konstruktor yang dihapus.

Cicipi di sini .

Luchian Grigore
sumber
3
Anda tidak perlu mendeklarasikan Foo () sama sekali, jika Anda mendeklarasikan Foo (int). Foo () tidak akan dibuat dan karenanya Foo f tetap tidak valid. Jadi contoh Anda tidak menunjukkan kasus untuk konstruktor yang dihapus. Lihat sendiri - ideone.com/mogiIF
tandai
1
@ Mark Saya menulis 2 konstruktor untuk membuktikan maksudnya. Saya akan mengedit agar jelas bagi semua orang.
Luchian Grigore
1
Saya memahami perbedaannya, saya hanya tidak memahami nilai tambah dari pernyataan delete secara umum dan untuk konstruktor pada khususnya. Bagaimanapun, saya dapat menentukan konstruktor default pribadi tanpa tubuh. Kemudian kode juga gagal, hanya selama penautan. Yah, saya dapat melihat bahwa penghapusan menyampaikan maksud secara lebih eksplisit, tetapi hanya itu saja.
tandai
11
@ Mark Ya, itu akan menjadi cara C ++ 98 dalam melakukan sesuatu. Tapi IMHO, menyampaikan maksud dengan jelas sebenarnya merupakan hal yang sangat penting dalam pemrograman secara umum. Dalam kasus ini, beberapa pembaca mungkin melihat konstruktor pribadi tidak terdefinisi dan menganggapnya tidak disengaja dan hanya menambahkan definisi untuknya, terutama jika definisi itu sepele seperti konstruktor default (Ya, memiliki komentar membantu, tetapi kami lebih suka kompilator -penegakan atas penegakan komentar). Dengan memperjelas maksud kita, kita juga mendapatkan pesan kesalahan yang jauh lebih baik yang mengatakan "dihapus secara eksplisit" daripada "referensi tidak ditentukan".
Taman
2
Sejujurnya saya tidak mengerti bagaimana ini menjawab pertanyaan utama. Pertanyaan dalam judul dan pertanyaan pertama OP di posting adalah: Kapan / mengapa saya ingin menghapus konstruktor saya secara eksplisit?
Alexander Bolinsky
13

mengapa secara eksplisit menghapus konstruktor?

Alasan lain:
Saya gunakan deleteketika saya ingin memastikan bahwa kelas dipanggil dengan penginisialisasi. Saya menganggapnya sebagai cara yang sangat elegan untuk mencapai ini tanpa pemeriksaan runtime.

Kompiler C ++ melakukan pemeriksaan ini untuk Anda.

class Foo
{
   public:
       Foo() = delete;
       Foo(int bar) : m_bar(bar) {};
   private:
       int m_bar;
}

Kode - sangat disederhanakan - ini memastikan bahwa tidak ada contoh seperti ini:Foo foo;

Peter VARGA
sumber
12
Deklarasi yang dihapus tidak diperlukan di sini. Ini secara otomatis dihapus dengan konstruktor yang disediakan pengguna
Mike Lui
5
Untuk memperjelas komentar oleh @MikeLui, deklarasi yang dihapus tidak diperlukan oleh compiler . Ada banyak kasus ketika kode seperti ini harus disertakan untuk menyatakan maksudnya kepada pemrogram lain .
Jeff G
Bersamaan dengan mendeklarasikan maksud Anda, ini menciptakan tempat yang jelas untuk mendokumentasikan alasan Anda untuk penghapusannya di antarmuka publik, dan sebagai tambahan kesalahan kompilator akan menjadi sesuatu yang singkat seperti "penggunaan fungsi yang dihapus". Jika Foomemiliki banyak konstruktor, bukan yang default, maka Foo foo;akan menyebabkan kesalahan yang lebih lama yang mencantumkan semua konstruktor yang didefinisikan secara implisit, dilindungi, dan privat yang gagal dicocokkan.
sigma
Saya masih belum mengerti berapa baris tambahan dengan deklarasi konstruktor yang kata kunci "= delete" menyatakan niat "tidak ada konstruktor default" lebih baik daripada ... hanya tidak ada konstruktor default? Contoh: Saya tidak ingin mendeklarasikan variabel "a" dalam kode saya - apa yang lebih baik, menulis "// int a; // tidak perlu mendefinisikan variabel a" atau tidak menulis apa pun tentang variabel ini dalam kode?
Ezh
2

Saya telah bertemu dengan ctors default yang dideklarasikan sebagai 'dihapus' di kode sumber LLVM (di AlignOf.h misalnya). Templat kelas terkait biasanya dalam namespace khusus yang disebut 'llvm :: detail'. Seluruh tujuan di sana saya pikir adalah bahwa mereka menganggap kelas itu hanya sebagai kelas penolong. Mereka tidak pernah bermaksud untuk memberi contoh; hanya untuk menggunakannya dalam konteks template kelas lain dengan beberapa trik metaprogramming yang berjalan dalam waktu kompilasi.

Misalnya. ada template kelas AlignmentCalcImpl yang hanya digunakan dalam template kelas lain yang disebut AlignOf sebagai parameter untuk operator sizeof (.). Ekspresi tersebut dapat dievaluasi dalam waktu kompilasi; dan tidak perlu membuat contoh template -> jadi mengapa tidak mendeklarasikan ctor delete default untuk mengekspresikan maksud ini.

Tapi itu hanya asumsi saya.

gybacsi.dll
sumber