2016-11-25 22 views
5

basit struct böyleneden bir harekete geçirici ekleyen ilk liste listesini devre dışı bırakıyor? Ile

olarak
struct Foo { int i; }; 
Bir başlatıcı listesi kullanarak yeni bir örneğini oluşturabilir

; Şimdi bir hamle yapıcısı

struct Bar 
{ 
    int i; 
    Bar(Bar&& other) { i = other.i; } 
}; 
başlatıcı artık çalışmıyor

eklerseniz

Foo foo { 314 }; 

ve ben de bir yapıcı eklemek zorunda: gerek bir kurucu yazmaya

Bar(int i) : i(i) {} 

I Bu davranışın bir şekilde this answer (user-defined move-constructor disables the implicit copy-constructor? için) ile ilgili olduğunu tahmin ediyorum, ancak daha fazla ayrıntı güzel olurdu.

Düzenleme: Düzenlemelerde belirtildiği gibi, bu bir kurucu eklemeyle ilgilidir.

(evet, bu aslında varsayılan yapı başlatıcısı rağmen "hareket" için biraz farklı bir sözdizimi ile tekrar çalışır

olduğunu

struct Baz 
{ 
    int i; 

    Baz& operator=(Baz&& other) 
    { 
     this->i = other.i; 
     return *this; 
    } 
}; 
: Sadece bir hareket operatörü eklerseniz sırayla Hangi tür bir tutarsızlık oluşturmak gibi görünüyor

Baz baz{ 3141 }; 
Baz b; 
b = std::move(baz); 
+0

, 'b' varsayılan inşa olacak ve atanan hareket, sadece farklı değil sözdizimi –

+3

keşke gerçek vaka farklı olduğunu varsayalım ama hareket semantik hakkında hiçbir şeyin sizi gerektirir unutmayın * Net * kaynak nesne (özellikle 'int's gibi önemsiz üyeleri değil). Sadece onu imha etmenin güvenli olduğu bir yerde bırakmak, mümkün olan tüm kaynakları yeniden kullanmak. Bir vektörün boş bir vektör için değiştirilmesi noktası, örneğin, temeldeki dizinin * sahipliğinin * (klonlanmış içeriklerin yerine) iletilmesidir ve yine de kaynakta bir şey vardır; Taşınan nesnenin boş içeriği olması gereklidir. –

+0

@ TheVee teşekkürler; kaynağı temizlememek için düzenlenmiş. –

cevap

3

O (yani başlamak orada bulunmayan sanık) hareket yapıcısı olarak devre dışıdır inşaat, ancak agrega inşaat değil başlatıcı listesidir. Ve iyi bir nedenden dolayı: özel bir kurucu ekleyerek, derleyiciye tam olarak 'daki bir toplamı topluluğuna değil, her bir üyesinde sadece tek tek çalışmaktan daha farklı bir şey olduğunu belirtiriz.

Bir toplam için, üye değişkenleri herhangi bir tür içermiyor olsa bile, varsayılan varsayılan, kopyala ve taşıyıcısı taşıyacaktır. Eğer başka bir nedenden dolayı kopyalama inşaat silip varsayılan başkalarını tutmak istiyorsanız sadece,

struct A { // non-copyable 
    int a; 
    int b; 
    A(int a_, int b_): a(a_), b(b_) { std::cout << "A(int,int)\n"; } 
    A() { std::cout << "A()\n"; } 
    A(const A&) = delete; 
    A(A&&) { std::cout << "A(A&&)\n"; } 
}; 

struct B { 
    A a; 
}; 

int main() { 
    B b1{{1,2}}; // OK: aggregate 
    B b2{std::move(b1)}; // OK: calls A::A(A&&) 
    //B b3{b1}; // error: B::B(const B&) auto-deleted 
} 

Ancak: onlara delege edilememesi halinde bir kopyası inşaat otomatik kullanışlı hareket inşaat bırakarak silinecek bu konuda açık ve net olması: Düzenlemenizle içinde

struct A { // copyable 
    int a; 
    int b; 
    A(int a_, int b_): a(a_), b(b_) { std::cout << "A(int,int)\n"; } 
    A() { std::cout << "A()\n"; } 
    A(const A&) { std::cout << "A(const A&)\n"; } 
    A(A&&) { std::cout << "A(A&&)\n"; } 
}; 

struct B { // non-copyable 
    A a; 
    B() = default; 
    B(const B&) = delete; 
    B(B&&) = default; 
}; 

int main() { 
    B b1{{1,2}}; // OK: still an aggregate 
    B b2{std::move(b1)}; // delegates to A::A(A&&) 
    //B b3{b1}; // error 
} 
+0

Mükemmel! '= Default' 'ın iyi kullanımlarına işaret ettiğiniz için teşekkür ederiz; Bu, kazan levhası veya "tören" kodunu azaltmak için uzun bir yol kat eder. –

+0

Bu cevaba gidiyorum çünkü örnek kodun yazılmasına (veya * yazılmamasına) ilişkin farklı yaklaşımların açıklanması daha iyi bir iş yapıyor. –

6

bu yapı bir agrega olduğundan bu sözdizimi aggregate initialization hiçbir kurucular olduğunda:) ama sonuç aynı hakkında görünüyor ve atama taşıyın. Bir yapıcı bu yapıyı ilave edilir

artık, toplam başlatma agrega kullanılamaz olduğu. kesin kurallar list initialization listelenen ilgili olanlardır: T türü bir cismin listesi başlatma

etkileri:

  • Aksi takdirde, T bir agregat tipinde ise, toplam başlatma olan seslendirdi. Aksi takdirde, T'nin kurucuları iki aşamada düşünülür: ...
3

Eğer aggregate initialization kullandığınız için hangi diyor ki: dizi türü:

Agrega başlatma bir agrega aşağıdaki türlerden biridir agrega başlatır liste başlatma bir biçimidir

  • hiçbir özel veya korumalı statik olmayan veri üyeleri
  • sahiptir sınıf tipi (genellikle yapı veya birlik),
  • hiçbir kullanıcı tarafından sağlanan, ,
  • hiçbir sanal (C++ 11 beri) kurucular (açıkça varsayılan veya silinmiş kurucular izin verilir) (C++ 17 beri) kalıtsal veya açık özel veya korunan temel sınıflar (C++ 17 beri)
  • hiçbir sanal üye fonksiyonları

Nokta 2 senin yapar dava başarısız.

+0

Teşekkürler; Herhangi bir "önerilen alternatif" var mı? Önemsiz olmayan bir şey için, kazan kodu bir baş belası olmaya başlar. –

+0

@Dan Kullanıcı tarafından sağlanan bir kurucuyu uygulamaya başladığınızda ne yazık ki, bir kurucu yazıp (şimdilik) yazmanız gerekecek. –

+1

@Dan POD (düz eski veri) türleri için sizinki gibi bir hareket yapıcıya sahip olmanın avantajı yoktur: aslında, belleğin sıfırlanmasıyla bilgisayarınızın aslında daha fazla işi olacaktır. Varsayılan kopya kurucu burada optimaldir, bu yüzden önerilen alternatif ekstra bir şey uygulamamaktır. –

İlgili konular