2015-10-24 41 views
6

Daha önce benzersiz ptr'leri kullanma hakkında bir sorum var. Yalnızca taşıma nesnelerini kullanmasını öneren this answer alırım. Ben aşağıdaki gibi bir sınıf tanımlamıştır:C++ 11'deki yalnızca nesne nesnelerini tanımlamak için bir nokta var mı?

class B { 
    const string objName; 
public: 

    B (B &&) = default; 
    B & operator= (B &&) = default; 
    B (const B &) = delete; 
    B & operator= (const B &) = delete; 

    B(const string & name) : 
      objName(name) { 

    } 

    virtual ~B(); 

    const string name() const { return objName;}; 
} 

ve bu çizgilerle B olarak adlandırılan:

class A { 
A(){} 
void take(B b); 
} 

A a; 
B b("test"); 
cout<<b.name(); 
a.take(std::move(b)); 
cout<<b.name(); 

Benim sorular: Ben hareket yapıcısı yapmayan bile

  1. Yapamam a.take (b) yazıp derleme hatası alıyorum. Kopyalama aracının silindiğini anlıyorum ama mantıksal bir seçim, std :: use a.take (b)
  2. gibi bir harekete ihtiyaç duyulmadan varsayılan olarak yapılandırıcıyı kullanmaktır. Sonuçta "test" iki kez yazdırılır. Arama yapıldıktan sonra neden b nesnesi kaldırılmamış? Eğer b nesnesi hala mevcutsa ve bir kopyası a.take'ye gönderilirse (move (b)), bu demektir ki, rivalue nesneler için herhangi bir hareketimiz yoktur.
  3. Yalnızca taşıma nesnelerini yukarıdaki gibi kullanmak iyi bir uygulamadır (Kopya oluşturucu ve atama işlecini kaldırma ve yapıcıyı varsayılan olarak taşı ve ödevi taşıma).
+0

daha uzun bir dize ile "test" değiştirmeyi deneyin ve neler olacağını görün. Genel olarak, taşınan nesnenin değeri belirsizdir; eski değer olabilir ya da olmayabilir. –

+3

Eğer ondan taşımak istiyorsanız 'const'' 'objectName' 'den kaldırmanız gerekir. –

+0

@AlanStokes kaldırma konsolu, bu sınamanın bir kez yazdırılmasına neden olur. Bu, const üyelerinin asla taşınmayacağı anlamına mı geliyor? Yoksa kopyalanacaklar mı? – Govan

cevap

4

Evet, bir nokta var. Nesneler arasında paylaşılamayan/edilmemesi gereken kaynakları (belki de fiziksel olanları) yöneten nesneler, akla gelen ilk örnektir.

1) Yanlış yazdınız. İşte bu soruya ve bir öncekine dayanarak istediğin şey.

class B { 
    string objName; 
public: 
    B (B &&) = default; 
    B & operator= (B &&) = default; 
    B (const B &) = delete; 
    B & operator= (const B &) = delete; 
    B(const std::string & name) : 
      objName(name) {} 
    virtual ~B() {} 
    std::string name() const { return objName;} 
}; 

class A { 
public: 
    std::vector<B> v; 
    void take(B && b) 
    { 
     v.push_back(std::move(b)); 
    } 
}; 

int main() 
{ 
    A a; 
    B b("test"); 

    std::cout << "Before: " << b.name() << std::endl; 
    a.take(std::move(b)); 
    std::cout << "After: " << b.name() << std::endl; 

    std::cout << "A has elements: " << std::endl; 
    for(B &b : a.v) 
     std::cout << " " << b.name() << std::endl; 
} 

2) Taşınan bir değere erişiyorsunuz, bu hiç mantıklı değil! This answer zaten açıklamakta iyi bir iş çıkarıyor, ancak aşağıda bir STL referansından std :: move için de metin ekledim.

http://en.cppreference.com/w/cpp/utility/move

Aksi belirtilmedikçe, geçerli ama belirtilmemiş durumuna getirilmesi taşındı olan tüm standart kütüphane nesneler. Yani, , yalnızca önkoşul olmayan işlevler, örneğin işleci gibi, taşındıktan sonra nesnede güvenle kullanılabilir.

3) Deneyimlerime göre iki meşru kullanım buldum. Her iki durumda da, yalnızca nesne nesneleri, iki nesne tarafından paylaşılırsa her şeyi parçalayacak bir fiziksel kaynağı kontrol eder.

+2

Kopya ctor ve atama işlecini açıkça silmeye gerek olmadığını unutmayın. Kullanıcı tanımlı hareket sözdizimi kopyalamayı devre dışı bırakır, bkz. Ör. canlı örnek [burada] (http://coliru.stacked-crooked.com/a/d20de6c4f219a22e). – vsoftco

+0

@tweej Neden unique-ptr yerine move-only objetcts kullanmalıyım? – Govan

+0

@Govan: Aslında paylaşılamayan bir kaynak için 'unique_ptr' bir bina tuğlasıdır ve sadece bir nesne taşımanız hoş bir arayüz sunmak için onu sarar. Eğer paylaşılamazsa, nasıl bir kopya kurucusu yazıyorsun? –

2

Yaklaşık 3: tabiki var. Her ne kadar, taşınabilecek, kopyalanamayacak ya da çekilemeyen birçok nesne örneği üzerinde düşünebilirim.

Bir örnek bir Soket sınıfıdır:
1) Hala bir IP veya bağlantı noktası almayan "boş" Soket için varsayılan bir kurucu vermek istiyorsunuz.
2) IP ve port alan bir kurucu vermek istersiniz.inşaat üzerine Soket bağlanmaya çalışır ve bağlantı)
3 başarısız bariz şey yoketme ise istisna atabilir - bu nesneyi kesmek ve bu nesne

tutabilir altta yatan herhangi bir sistem kaynaklarını serbest neyi kurucu vs kopya kurucu hakkında hareket?
Diyelim ki bir soket oluşturan bir işlev var ve onu döndürür.
yeni kopyalanan soket (dönüş değeri) kaynak soketi bağlandı aynı IP ve bağlantı noktasına bağlanmaya çalışır: Ne demek kopya kurucu çağırırsanız. Bu mümkün olmayabilir.
kaynak soket bağlantısı kesilmiş ve

sadece büyük bir karmaşa yaratacak soket kopyalamaya çalışırken oldukça mümkündür tahrip edilecektir. tam tersine , bir hareket yapıcı beutifully bu kütleyi çözer:
dönüş değeri onları ayırmadan veya onları yok etmeden tüm temel işletim sistemi kaynaklarını alırlar.
kaynak soket boş kalır ve yıkıcı kesmek veya yok etmek ilgisi yoktur.

o prizler sadece büyük bir ihtimalle, hareket kopyalanacak verecekleri anlaşılmaktadır.

bu bir "Süreç" sınıfına geçerli olabilir - Ben kopyalayarak bir süreç dönmek için çalışacağım, ben sadece orijinal kapatmaya, tekrar aynı işlemi açmaya olabilir ederim. Dağınıklık! tarafından hareket ettiriliyor. İşlemi işlevden işleve taşıyorum.

+0

Cevabınız için teşekkür ederiz. Taşıyıcı ve kopya arasındaki hareket ve farklılıklar ihtiyacını anlıyorum. Merak ettiğim şey, rengin nesneler için harekete ihtiyaç duymasıdır. Socket'i unique_ptr ile uygulayabilirsiniz. Soru, hareketler arasındaki farktır (unique_ptr (yeni Socket())) veya move (Socket()) – Govan