2012-10-29 19 views
16

Bir hareket kurucusunun bir kopya kurucusu olarak adlandırıldığı zaman kafam karıştı. okudum aşağıdaki kaynaklar:Move Constructor ne zaman çağırılır?

Move constructor is not getting called in C++0x

Move semantics and rvalue references in C++11

msdn

bu kaynaklardan tümü ya overcomplicated (Sadece basit bir örnek istiyorum) ya da yalnızca yazma göstermek yapıcıyı hareket ettir, ama nasıl çağırılacağını değil. Ive basit bir sorun daha spesifik olarak yazılmıştır:

const class noConstruct{}NoConstruct; 
class a 
{ 
private: 
    int *Array; 
public: 
    a(); 
    a(noConstruct); 
    a(const a&); 
    a& operator=(const a&); 
    a(a&&); 
    a& operator=(a&&); 
    ~a(); 
}; 

a::a() 
{ 
    Array=new int[5]{1,2,3,4,5}; 
} 
a::a(noConstruct Parameter) 
{ 
    Array=nullptr; 
} 
a::a(const a& Old): Array(Old.Array) 
{ 

} 
a& a::operator=(const a&Old) 
{ 
    delete[] Array; 
    Array=new int[5]; 
    for (int i=0;i!=5;i++) 
    { 
     Array[i]=Old.Array[i]; 
    } 
    return *this; 
} 
a::a(a&&Old) 
{ 
    Array=Old.Array; 
    Old.Array=nullptr; 
} 
a& a::operator=(a&&Old) 
{ 
    Array=Old.Array; 
    Old.Array=nullptr; 
    return *this; 
} 
a::~a() 
{ 
    delete[] Array; 
} 

int main() 
{ 
    a A(NoConstruct),B(NoConstruct),C; 
    A=C; 
    B=C; 
} 

anda, A, B ve C farklı işaretçi değerlerine sahiptir. A'nın yeni bir işaretçiye sahip olmasını isterim, B'nin C eski işaretçisine sahip olması ve C'nin boş bir işaretçisine sahip olmasını istiyorum.

biraz konu dışı, ama bir ben minnettar olacaktır ayrıntılı olarak bu yeni özellikleri hakkında bilgi verebilir ve muhtemelen çok daha fazla soru sormak gerek olmazdı bir dokümantasyon önermek olsaydı. Her şeyden

+0

, kopyalamayı kontrol etmek istiyorum ve tahsis edilmesi için deyim http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom takas olabilir Şebeke. – undu

+0

[related FAQ] (http: // stackoverflow.com/questions/3106110 /) – fredoverflow

cevap

22

bir hareket yapıcı olarak adlandırılır:

  • bir amacı, başlatıcı std::forward<T>(something) ve T mükemmel" şablon programlama yararlı olan bir lvalue başvuru türü (değilken bir amacı, başlatıcı std::move(something)
  • olduğunda bir nesne başlatıcısı bir geçicidir ve derleyici kopyasını ortadan kaldırmaz zaman
  • /tamamen
  • hareket) "yönlendirme 10
  • değerine göre bir fonksiyon yerel sınıf nesnesini geri gönderirken ve derleyici kopya yok etmez/işlev yerel sınıf nesnesi atma ve derleyici kopya yok etmez zaman tamamen
  • /
tamamen hareket hareket

Bu tam bir liste değildir. Parametrenin bir sınıf türüne (referans değil) sahip olması durumunda, bir "nesne başlatıcısı" nın bir işlev argümanı olabileceğini unutmayın.

kısmen ilgili konu ise
a RetByValue() { 
    a obj; 
    return obj; // Might call move ctor, or no ctor. 
} 

void TakeByValue(a); 

int main() { 
    a a1; 
    a a2 = a1; // copy ctor 
    a a3 = std::move(a1); // move ctor 

    TakeByValue(std::move(a2)); // Might call move ctor, or no ctor. 

    a a4 = RetByValue(); // Might call move ctor, or no ctor. 

    a1 = RetByValue(); // Calls move assignment, a::operator=(a&&) 
} 
4

Öncelikle, kopya yapıcı bozuldu. Kopyalanan ve kopyalanan nesnelerin her ikisi de aynı Array işaret edecek ve her ikisi de kapsam dışı olduğunda, tanımsız davranışla sonuçlanırsa delete[]'u dener. Düzeltmek için dizinin bir kopyasını yapın. Eğer bunu istiyorum hem atama ifadeleri yerine SağDeğerler kullanmak yerine, SolDeğerler gelen atama çünkü

a::a(const a& Old): Array(new int[5]) 
{ 
    for(size_t i = 0; i < 5; ++i) { 
    Array[i] = Old.Array[i]; 
    } 
} 

Şimdi, taşıma atama, yapılmamaktadır. Hareketlerin gerçekleştirilebilmesi için, bir değerden hareket etmelisiniz, ya da bir değerin bir değer olarak kabul edilebileceği bir bağlam olmalıdır (bir işlevin dönüş ifadesi gibi).

istenen etki, bir rvalue referans oluşturmak için std::move kullanmak için.

A=C;    // A will now contain a copy of C 
B=std::move(C); // Calls the move assignment operator 
+0

'B = std :: move (C); // Kopyalama ataması operatörünü çağırır 'Hareket ataması operatörü olmasın mı? Daha sonra, C artık eskiden olduğu gibi olmayabilir. – RainingChain

+0

@RainingChain Evet, bu bir yazım hatası oldu, teşekkürler! – Praetorian

İlgili konular