yapıcı neden açıkça silinsin?


95

Yapıcımı ne zaman / neden açıkça silmek isteyeyim? Sebebin kullanımını engellemek olduğunu varsayarsak, neden sadece yapmayasınız private?

class Foo
{ 
  public: 
    Foo() = delete; 
};

14
Bu tür iyi gider arasında = default, hatta sınıf kullanabilirsiniz, ve ben şahsen görme tercih silinen fonksiyonun kullanın. over Function özeldir. İlki açıkça "Bunun kullanılması amaçlanmamıştır" diyor. Bundan bir şey çıkarsa, sınıfın onu kullanamaması anlamsal bir fark yaratır.
chris

16
Açıkçası insanların yakın oylarla saldırganlaşmaya başladığını düşünüyorum. Bunun ne kadar yapıcı olmadığını anlamıyorum.
Luchian Grigore

4
@LuchianGrigore: Kabul edildi. Topluluğun neden bu kadar katı hale geldiğini merak ediyordum. Asıl noktayı görmüyorum.
Ed S.

11
C ++ 11'i nadiren kullandığım için, bu benim için OP'nin muhtemelen fark ettiğinden daha fazla bilgilendirici. Ben bile bilmiyordum olabilir için bir kurucu etiketlemek delete. Hem soru hem de Luchian'ın cevabı kolaylıkla yapıcı olarak nitelendirilebilir. C ++ 11'in ince noktalarını solumayan ancak yakında her ikisinden de bir şeyler alması gerekecek olan herkes.
WhozCraig

Yanıtlar:


89

Peki ya:

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

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

karşı

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

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

Temelde farklı şeylerdir. privatesadece sınıfın üyelerinin bu yöntemi çağırabileceğini veya bu değişkene (veya elbette arkadaşlarına) erişebileceğini söyler. Bu durumda, o staticsınıfın (veya başka herhangi bir üyenin) bir yönteminin privatebir sınıfın yapıcısını çağırması yasaldır . Bu, silinmiş kurucular için geçerli değildir.

Buradan örnek alın .


3
Foo (int) bildirirseniz, Foo () bildirmenize hiç gerek yoktur. Foo () oluşturulmayacak ve dolayısıyla Foo f zaten geçersiz. Dolayısıyla, örneğiniz silinmiş kurucunun durumunu göstermez. Kendiniz görün - ideone.com/mogiIF
işaretleyin

1
@mark Bu noktayı kanıtlamak için 2 kurucu yazdım. Herkesin anlayabileceği şekilde düzenleyeceğim.
Luchian Grigore

1
Farkı anlıyorum, sadece genel olarak delete ifadesinin ve özellikle bir kurucu için katma değerini anlamıyorum. Sonuçta, gövde olmadan özel bir varsayılan kurucu belirtebilirim. Ardından kod, yalnızca bağlantı sırasında başarısız olur. Şey, silme işleminin niyeti daha açık bir şekilde ifade ettiğini görebiliyorum, ama hepsi bu.
işaretleyin

11
@mark Evet, işleri yapmanın C ++ 98 yolu bu olurdu. Ancak IMHO, niyeti açıkça iletmek aslında genel olarak programlamada çok önemli bir şey. Bu durumda, bazı okuyucular özel tanımlanmamış bir kurucu görebilir ve bunun tesadüfi olduğunu varsayabilir ve bunun için bir tanım ekleyebilir, özellikle de tanım varsayılan bir kurucu kadar önemsiz ise (Evet, yorum yapmak yardımcı olur, ancak biz daha çok derleyiciyi tercih ederiz -Yorum yaptırımı üzerinde yaptırım). Niyetimizi daha net hale getirerek, "tanımsız referans" yerine "açıkça silindi" yazan çok daha iyi bir hata mesajı da alıyoruz.
mpark

2
Dürüst olmak gerekirse, bunun ana soruyu nasıl yanıtladığını anlamıyorum. Başlıktaki soru ve OP'nin gönderideki ilk sorusu şuydu: Kurucumu ne zaman / neden açıkça silmek isteyeyim?
Alexander Bolinsky

13

yapıcı neden açıkça silinsin?

Başka neden:
Kullandığım deleteBir sınıf bir ilklendiricili denir sağlamak istediğinizde. Bunu, çalışma zamanı kontrolleri olmadan gerçekleştirmenin çok zarif bir yolu olarak görüyorum.

C ++ derleyicisi bu denetimi sizin için yapar.

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

Bu - çok basitleştirilmiş - kod, böyle bir örneklemenin olmamasını sağlar:Foo foo;


12
Silinen beyanname burada gereksizdir. Kullanıcı tarafından sağlanan herhangi bir kurucu ile otomatik olarak silinir
Mike Lui

5
@MikeLui tarafından yapılan yorumu netleştirmek için, silinen bildirim derleyici için gereksizdir . Diğer programcılara niyet beyan etmek için bunun gibi kodların dahil edilmesi gereken çok sayıda durum vardır .
Jeff G

Niyetinizi bildirmenin yanı sıra, genel arayüzde silinme nedeninizi belgelemek için açık bir yer yaratır ve ek olarak derleyici hatası "silinen işlevin kullanımı" gibi kısa bir şey olacaktır. Çok Foosayıda kurucuya sahip olsaydı, sadece varsayılan bir kurucu yoksa , Foo foo;eşleşemediği tüm örtük olarak tanımlanmış, korumalı ve özel kurucuları listeleyen çok daha uzun bir hataya neden olurdu.
sigma

"= Delete" anahtar kelimesinin yapıcı bildirimi ile ekstra satırın "varsayılan kurucu yok" fikrinin niyetini "varsayılan kurucu olmaması" ndan daha iyi açıkladığını hala anlamıyorum? Örnek: Kodumda "a" değişkenini bildirmek istemiyorum - hangisi daha iyi, "// int a; // değişken a" tanımlamaya gerek yok veya kodda bu değişken hakkında hiçbir şey yazmama?
Ezh

2

LLVM kaynak kodunda (örneğin AlignOf.h dosyasında) 'silinmiş' olarak bildirilen varsayılan ctors ile tanıştım. İlişkili sınıf şablonları genellikle 'llvm :: detail' adlı özel bir ad alanında bulunur. Bence oradaki tüm amaç, o sınıfı yalnızca yardımcı bir sınıf olarak görmeleriydi. Onları somutlaştırmayı asla amaçlamadılar; bunları yalnızca derleme zamanında çalışan bazı meta programlama hileleriyle diğer sınıf şablonları bağlamında kullanmak için.

Örneğin. sadece AlignOf adlı başka bir sınıf şablonunda sizeof (.) operatörü için bir parametre olarak kullanılan bu AlignmentCalcImpl sınıf şablonu vardır. Bu ifade derleme zamanında değerlendirilebilir; ve şablonun somutlaştırılmasına gerek yoktur -> öyleyse neden bu niyeti ifade etmek için varsayılan ctor delete'ı bildirmiyorsunuz?

Ama bu sadece benim varsayımım.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.