2014-10-21 30 views
10

Biraz araştırma yaptıktan sonra, yazıcının/devredilebilir olmasını gerektiren, C++11 has a defect allocators ile görüyorum. Eminim bu sorunun nedeni budur, ancak silinmiş ve beyan edilmemiş taşıma semantiği arasındaki davranış hakkında kafam karıştı. Silinen taşıma semantiği neden std :: vector ile sorunlara yol açıyor?

Ben MSVC12 ve Clang hem derlenmeyecektir aşağıdaki kodu: ( live sample)

xmemory0(600): error C2280: 'Copyable::Copyable(Copyable &&)' : attempting to reference a deleted function

Ve Clang tarih::

Bu ile MSVC üzerinde derlenmeyecektir

#include <vector> 

class Copyable 
{ 
public: 
    Copyable() = default; 

    Copyable(Copyable const& other) 
     : m_int(other.m_int) 
    {} 

    Copyable& operator= (Copyable const& other) 
    { 
     m_int = other.m_int; 
     return *this; 
    } 

    Copyable(Copyable&&) = delete; 
    Copyable& operator= (Copyable&&) = delete; 

private: 
    int m_int = 100; 
}; 

int main() 
{ 
    std::vector<Copyable> objects; 
    objects.push_back(Copyable{}); 
} 

new_allocator.h:120:23: error: call to deleted constructor of 'Copyable'

Her iki durumda da, açıkça silinen taşıma yapısını/atamasını kaldırdığımda yöntemler, kod derler. AFAIK, kopya atama/oluşturma yöntemlerini bildirdiğinizde derleyici, ilgili taşıma üyelerini örtülü olarak bildirmez. Bu yüzden hala etkin bir şekilde silinmeli, değil mi? Hareket yapısı/atamasının açık bir şekilde silinmesini kaldırdığımda kod neden derleniyor?

Genel olarak bu C++ 11 hatası için iyi bir çözüm nedir? Nesnelerimin hareketli olmasını istemiyorum (ancak kopyalanabilirler).

+0

Bir kopyasını kullanarak harekete geçin? –

+0

Ayrıca, ilgili: [Neden C++ 11-Silinen fonksiyonlar aşırı yük çözünürlüğüne katılır?] (Http: // stackoverflow.com/questions/14085620/why-do-c11-silindi-functions-aşırı-yük-çözünürlükte) – Nawaz

cevap

14

Bir fonksiyonun silinmesi, bildirilmemesiyle aynı şey değildir.

Silinmiş bir işlev bildirilmiş ve aşırı yük çözünürlüğüne katılır, ancak aramayı denerseniz, bir hata üretilir.

Taşınacak kurucunuzu bildirmezseniz, derleyici bir kopya oluşturucusu oluştururken bir tane oluşturmaz. Bir rengin üzerindeki aşırı yük çözünürlüğü, kopya yapıcınızı bulacaktır, muhtemelen istediğinizi budur.

foo(foo&&)=delete ile söylediğin şey "kimse bu nesneyi oluşturmaya çalışırsa, bir hata oluştur" idi.

void do_stuff(int x) { std::cout << x << "\n"; } 
void do_stuff(double) = delete; 

void do_stuff2(int x) { std::cout << x << "\n"; } 
//void do_stuff2(double) = delete; 

int main() { 
    do_stuff(3); // works 
    //do_stuff(3.14); // fails to compile 
    do_stuff2(3); // works 
    do_stuff2(3.14); // works, calls do_stuff2(int) 
} 

bu biraz daha kafa karıştırıcı yapar yukarıdaki sorunla tek parça özel üye fonksiyonları otomatik olarak biraz gizli kuralları kapalı tabanlı oluşturulan veya olmamasıdır:

Burada farkı göstermek olabilir.

10
Copyable(Copyable&&) = delete; 
Copyable& operator= (Copyable&&) = delete; 

siz taşıma semantik bir uzman değilseniz (ve Yani, gerçekten bilgili ), özel hareket üyelerini silmek asla. İstediğin şeyi yapmayacak. Bir başkasının bunu yapmış olduğu kodu incelerseniz, onu arayın. Açıklama gerçekten sağlam olmalı ve "tipin hareket etmesini istemiyorum."

Sadece bunu yapma.

İstediğiniz şeyi yapmanın doğru yolu, yalnızca kopya üyelerinizi bildirmek/tanımlamaktır. Hareket üyeleri gizli olarak engellenir (silinmez, ancak aslında orada değildir). Sadece C++ 98/03 yaz.

Ayrıntılar için, see this answer.

+1

+1 Bu, orada bir çok yararlı referans olsa da, bulunması zor pratik tavsiyedir. –

+2

Küçük bir kitabı, bu harika şeylerle (semantikleri, parametre geçişlerini, sınıf tasarımlarını, tarihleri, permütasyonları ve iplikleri) SO ile (ve libC++ içinde kullanılan) yıllar içinde buraya koyduğunuzu nasıl yazabilirsiniz? @ShafikYaghmour'un doğru olarak belirttiği gibi, bulması ve dağılması çok zor. – TemplateRex

+0

@TemplateRex: Aradığı zaman ... –

İlgili konular