Kopya oluşturucuyu devre dışı bırak


173

Sınıfım var :

class SymbolIndexer {
protected:
  SymbolIndexer ( ) { }

public:
  static inline SymbolIndexer & GetUniqueInstance ( ) 
  { 
    static SymbolIndexer uniqueinstance_ ;
    return uniqueinstance_ ; 
  }
};

Aşağıdaki gibi kodu devre dışı bırakmak için nasıl değiştirmeliyim:

SymbolIndexer symbol_indexer_ = SymbolIndexer::GetUniqueInstance ( );

ve yalnızca aşağıdaki gibi kodlara izin ver:

SymbolIndexer & ref_symbol_indexer_ = SymbolIndexer::GetUniqueInstance ( );

1
Btw, bu miras hükümleri olan bir tekton mu?
R. Martinho Fernandes

Kodunuzda her zaman farklı örnek oluşturulacak bir şüphe var GetUniqueInstance () her zaman aynı nesneye başvuru verecektir düşünüyorum.
Pratham Shah

Yanıtlar:


286

Kopya oluşturucuyu özel yapabilir ve hiçbir uygulama sağlayamazsınız:

private:
    SymbolIndexer(const SymbolIndexer&);

Veya C ++ 11'de açıkça yasaklayın:

SymbolIndexer(const SymbolIndexer&) = delete;

43
deleteAnahtar kelime ile ilgili olarak aşağıdakileri eklemek istiyorum. Yeni bir sınıf tasarlarken şu anki alışkanlığım hemen deletehem kopya oluşturucuya hem de atama operatörüne. Bağlama bağlı olarak, çoğunlukla gereksiz olduklarını ve bunları silmenin bazı beklenmedik davranış vakalarını önlediğini gördüm. Bir kopyalayıcıya ihtiyaç duyulabilecek bir durum ortaya çıkarsa, hareket semantiği ile yapılıp yapılamayacağını belirleyin. Bu istenmeyen bir durumsa, hem kopyalayıcı hem de atama operatörü için bir uygulama sağlayın. Bu iyi bir yaklaşım olsun, okuyucuya bırakacağım.
pauluss86

1
@ pauluss86 Yaklaşımınızı seviyorum ama bu kalıbı takip etmek için harcanan zamanın önlediği hataların sağladığı zamandan daha fazla olduğunu düşündüğüm için tam olarak taahhüt etmem. Emin olmadığımda kopyalamayı yasaklıyorum.
Tomáš Zato - Monica'yı

@ pauluss86 Rust'un yaptığı budur: Varsayılan olarak taşı (ve varsayılan olarak sabit). Bence çok yardımcı.
Kapichu

33

Birden fazla mirasın sakıncası yoksa (sonuçta o kadar da kötü değil), özel kopya oluşturucu ve atama operatörü ile basit bir sınıf yazabilir ve ek olarak alt sınıflandırabilirsiniz:

class NonAssignable {
private:
    NonAssignable(NonAssignable const&);
    NonAssignable& operator=(NonAssignable const&);
public:
    NonAssignable() {}
};

class SymbolIndexer: public Indexer, public NonAssignable {
};

GCC için bu aşağıdaki hata iletisini verir:

test.h: In copy constructor ‘SymbolIndexer::SymbolIndexer(const SymbolIndexer&)’:
test.h: error: ‘NonAssignable::NonAssignable(const NonAssignable&)’ is private

Bunun her derleyicide çalışacağından pek emin değilim. Orada bir olan ilgili soru , ancak henüz hiçbir cevap.

UPD:

C ++ 11'de NonAssignablesınıfı aşağıdaki gibi de yazabilirsiniz :

class NonAssignable {
public:
    NonAssignable(NonAssignable const&) = delete;
    NonAssignable& operator=(NonAssignable const&) = delete;
    NonAssignable() {}
};

deleteBir türetilen sınıfın varsayılan inşa üyeleri de kullanılamaz böylece anahtar kelime önler üyeleri, varsayılan inşa edilmektedir. Atamaya çalışmak GCC'de aşağıdaki hatayı verir:

test.cpp: error: use of deleted function
          ‘SymbolIndexer& SymbolIndexer::operator=(const SymbolIndexer&)’
test.cpp: note: ‘SymbolIndexer& SymbolIndexer::operator=(const SymbolIndexer&)’
          is implicitly deleted because the default definition would
          be ill-formed:

UPD:

Boost zaten aynı amaç için bir sınıfa sahip, sanırım aynı şekilde uygulandı. Sınıf çağrılır boost::noncopyableve aşağıdaki gibi kullanılması amaçlanır:

#include <boost/core/noncopyable.hpp>

class SymbolIndexer: public Indexer, private boost::noncopyable {
};

Proje politikanız izin veriyorsa Boost'un çözümüne bağlı kalmanızı tavsiye ederim. Daha fazla bilgi için boost::noncopyableilgili başka bir soruya da bakın .


Olmamalı NonAssignable(const NonAssignable &other);mı?
Troyseph

Bence bu soru C ++ 11 deleteanahtar kelime sözdizimine güncellenmiş olsaydı yol daha fazla oy alır .
Tomáš Zato - Monica'yı

@ TomášZato: Fikir, kopya oluşturucu ve atama operatörünü mevcut, ancak özel tutmaktır. Eğer deleteonlar, o çalışmayı durdurur (az önce kontrol ettim).
firegurafiku

@ TomášZato: Ah, üzgünüm, test yöntemim biraz yanlıştı. Silme de işe yarar. Cevabı bir dakika içinde güncelleyecek.
firegurafiku

3
@Troyseph: const Class&ve Class const&hemen hemen aynı. İşaretçiler için yazımınız bile olabilir Class const * const.
firegurafiku

4

Make SymbolIndexer( const SymbolIndexer& )özel. Bir referansa ataıyorsanız, kopyalamıyorsunuzdur.

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.