SORU
23 HAZİRAN 2010, ÇARŞAMBA


Taşıma semantiği nedir?

Ben sadece Yazılım Mühendisliği radyo podcast interview with Scott Meyers C 0x ile ilgili dinleme bitirdi. Yeni özelliklerin çoğu bana mantıklı geldi, ve aslında şimdi C 0 x, biri hariç heyecanlıyım. Ben hala alamadımtaşıma semantiği... Ne tam olarak?

CEVAP
24 HAZİRAN 2010, PERŞEMBE


En kolay örnek kod ile hareket semantiği anlamak benim için zor. Hadi sadece öbek ayrılan bellek bloğu: bir işaretçi tutan çok basit bir string sınıfı ile Başlat

#include <cstring>
#include <algorithm>

class string
{
    char* data;

public:

    string(const char* p)
    {
        size_t size = strlen(p)   1;
        data = new char[size];
        memcpy(data, p, size);
    }

Bellek kendimizi yönetmek için seçtik beri rule of three takip etmeliyiz. Atama operatörü yazma erteleme ve sadece şimdi için yıkıcı ve kopya yapıcı uygulamak için gidiyorum:

    ~string()
    {
        delete[] data;
    }

    string(const string& that)
    {
        size_t size = strlen(that.data)   1;
        data = new char[size];
        memcpy(data, that.data, size);
    }

Kopyalama kurucusu string nesneleri kopyalamak için ne anlama geldiğini tanımlar. Parametre const string& that aşağıdaki örneklerde kopyaları yapmanızı sağlar hangi tür dize tüm ifadeler için bağlar:

string a(x);                                    // Line 1
string b(x   y);                                // Line 2
string c(some_function_returning_a_string());   // Line 3

Şimdi hareket semantiği içine anahtar bakış. Not yalnızca ilk satırını nerede anlaşıldı x bu derin kopyasını gerçekten gerekli, çünkü biz belki incelemek x sonraki ve çok da şaşırdım x değişti bir şekilde. Dedim x üç kez (eğer bu cümleyi sayarsak dört kez) ve ne kadar fark ettinizaynı nesneher zaman? x gibi ifadeler "diyoruz". lvalues

Satır 2 ve 3 değişkenleri temel string nesneleri isim yok çünkü lvalues, ama rvalues değil, istemci yine zaman içinde daha sonraki bir noktada onları incelemek için bir yol vardır. rvalues sonraki noktalı virgül (daha doğrusu: lexically bu rvalue içeren tam ifade) sonunda yok olan geçici nesneleri göstermek. Bu b c, başlatma sırasında kaynak dizesi ile istediğimiz her şeyi yapabiliriz çünkü . önemlidir ^em>istemci bir fark göremedim!

C 0x yeni bir mekanizma "olan, diğer şeyler arasında,başvuru" rvalue tanıttı bize fonksiyon aşırı yükleme ile rvalue bağımsız değişkenleri tespit etmek için izin verir. Tek yapmamız gereken rvalue reference parametresi ile bir kurucu yazmak. Sınıf içinde yapabilirizbir şey istiyoruzkaynak, içinde gidiyoruz sürecebazıgeçerli durum:

    string(string&& that)   // string&& is an rvalue reference to a string
    {
        data = that.data;
        that.data = nullptr;
    }

Burada ne yaptık? Derin yığın veri kopyalamak yerine, sadece işaretçiyi bir kopyasını aldık ve sonra özgün işaretçi null olarak ayarlayın. Sonuç olarak, "" başlangıçta kaynak dizesi. ait veri çaldık Yine, anahtar fikir olabilir hiçbir koşul altında müşteri kaynağı değiştirilmiş olduğunu tespit eder. Gerçekten bir kopyasını burada yapmayız beri, bu yapıcı "diyoruz". hareket kurucu Onun işi onları kopyalamak yerine başka bir nesneden kaynakları taşımaktır.

Tebrikler, artık hareket semantiği temellerini anlamak! Devam atama operatörünü uygulayarak izin verin. Eğer aşina değilseniz, 32**, Öğren ve Başar C-bir deyim istisna güvenliği ile ilgili, çünkü geri gel.

    string& operator=(string that)
    {
        std::swap(data, that.data);
        return *this;
    }
};

Ha, bu kadar mı? "Nerede rvalue başvuru var?" diye sorabilirsiniz. "Burada ihtiyacımız yok" cevabım :)!

Parametre that geçiyoruz unutmayındeğeryani that sadece başka bir dize nesne gibi başlatılması gerekiyor. Tam olarak nasıl that başlatılmış olacak? C 98 eski zamanlarda bir cevap olurdu "kopya yapıcı tarafından". C 0 x, derleyici atama operatörü değişken bir lvalue veya bir rvalue olup olmamasına göre kopya Kurucu ve kurucu arasında seçer.

Eğer öyleyse dediğin a = bkurucu kopyalayınthat başlatılacaktır ifade b bir lvalue (çünkü), ve atama operatörü taze oluşturulan, derin bir kopyasını içeriğini değiştirir. -- Bir kopyasını yapmak, kopyasını içeriğini değiştirin ve sonra kapsam bırakarak kopyasını kurtulmak kopyalama ve takas deyim tanımı. Yeni bir şey yok burada.

Ama eğer a = x y, diyorsanızyapıcı hareketthat başlatılacaktır 26 ** ifadesi bir rvalue (çünkü), hiç bir derin kopyasını dahil, sadece etkili bir hareket yoktur. that hala inşa önemsiz olduğunu fakat bu tartışma, bağımsız bir nesnedir yığın veri kopyalanacak olmadığı için hareket etti. x y bir rvalue çünkü kopyalamak için gerekli değildi, ve yine, string nesneleri rvalues ile belirtilen yere gitmek sorun değil.

Özetlemek gerekirse, kopya yapıcı kaynağı kalması gerekir, çünkü derin bir kopyasını yapar. Hareket yapıcı, diğer yandan, sadece işaretçi kopyalayın ve sonra da boş bir kaynak işaretçisi ayarlayın. Tamam "" kaynak istemci nesnenin yeniden inceleme yolu vardır çünkü bu şekilde nesne. iptali için

Bu örnek üzerinde ana noktası var umuyoruz. Ben çok isteyerek terk eden rvalue başvuruları ve hareket semantiği daha basit tutmak için var. Eğer daha fazla ayrıntı istiyorsanız lütfen my supplementary answer bkz.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • The White House

    The White Ho

    21 Ocak 2006
  • Vortez

    Vortez

    27 Temmuz 2009
  • Whizzpopping

    Whizzpopping

    10 Kasım 2005