SORU
15 Mayıs 2010, CUMARTESİ


Aşırı başvuru, pass-by-value std::karşı tek hareket?

Ana tavsiyem C 0 x var rvalues derleyicileri varsayılan-onları uygulamak kadar hareket kurucular ekleyin ve tüm sınıflar için operatörler taşımaktır ile ilgili gibi görünüyor.

Ama bekliyorsa otomatik nesil muhtemelen VC10 SP1 ya da en kötü durumda, VC11 kadar burada olmayacak, çünkü VC10, kullanırsanız kaybeden bir strateji. Büyük olasılıkla, bunun için beklemeye yıl içinde ölçülür.

Burada yatan benim sorunum. Tüm bu yinelenen kod yazmak eğlenceli değil. Ve tatsız bir bak. Ama bu yük, bu sınıflar yavaş kabul için iyi karşılandı. Daha küçük sınıfları, yüzlerce, binlerce değilse bile değil yani.

::iç:: C 0 x yazmama izin gerekiyordudaha azkod, daha fazla değil!

Ve sonra aklıma bir şey geldi. Birçok kişi tarafından paylaşılan, tahmin ediyorum.

Neden sadece değer her şey gerçek değil mi? Std olmaz::kopyala elision bu neredeyse en iyi hareket?

Örnek 1 - Pre-0x yapıcı Tipik

OurClass::OurClass(const SomeClass& obj) : obj(obj) {}

SomeClass o;
OurClass(o);            // single copy
OurClass(std::move(o)); // single copy
OurClass(SomeClass());  // single copy

Eksileri:Rvalues için harcanmış bir kopyası.

2 - C 0 x Önerilen örnek?

OurClass::OurClass(const SomeClass& obj) : obj(obj) {}
OurClass::OurClass(SomeClass&& obj) : obj(std::move(obj)) {}

SomeClass o;
OurClass(o);            // single copy
OurClass(std::move(o)); // zero copies, one move
OurClass(SomeClass());  // zero copies, one move

Artıları:Muhtemelen en hızlı.
Eksileri:Çok fazla kod!

3 - -by Pass-değer std::örnek hareket

OurClass::OurClass(SomeClass obj) : obj(std::move(obj)) {}

SomeClass o;
OurClass(o);            // single copy, one move
OurClass(std::move(o)); // zero copies, two moves
OurClass(SomeClass());  // zero copies, one move

Artıları:Ek bir kod.
Eksileri:Durumlarda boşa bir hamle 1 & 2. Performans SomeClass hareket kurucu varsa büyük acı çekecek.


Ne düşünüyorsun? Bu doğru mu? Yapılan hareket kodu azaltılması yararı nazaran kabul edilebilir bir kayıp mı?

CEVAP
9 HAZİRAN 2010, ÇARŞAMBA


Bu konuda yeni olduğumu ve biraz araştırma yaptım, çünkü söz konusu ilgimi çekti. Sonuçları bana takdim edeyim.

İlk olarak, iç çekişin.

enter code here::iç:: C 0 x bana daha az kod yazmak için izin, daha fazla değil! güya

ayrıca beklenen ne kod üzerinde daha iyi bir kontrol sağlamak için. Ve bunu yapar. Ekstra bir yapıcı binmezdim:

OurClass::OurClass(SomeClass&& obj) : obj(std::move(obj)) {}

Ben beni tutar çünkü kişisel olarak karmaşık ve önemli durumlarda tercih ayrıntı, ve benim kod Olası okuyucuları uyardı.

al, örneğin, C-style cast (T*)pT ve C standardı static_cast<T*>(pT) Çok daha ayrıntılı ama büyük bir adım.

İkinci olarak, bir bit Örneği hakkında şüpheli olduğu 3, son test çalışması. Başka bir hareket rvalue-by-value geçirilen parametre oluşturmak için yapıcı ilgisi olabileceğini düşündüm. Benim yeni VS2010 biraz hızlı proje oluşturulur ve bazı açıklamalar var. Kodu olduğu gibi burada da sonuçlarını yayınlayacağız.

kaynak:

// test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <utility>
#include <iostream>

class SomeClass{
    mutable int *pVal;
public:
    int Val() const { return *pVal; };
    SomeClass(int val){
        pVal = new int(val);
        std::cout << "SomeClass constructor(pVal = 0x" << std::hex << pVal << std::dec << ")" << std::endl;
    }
    SomeClass(const SomeClass& r){
        pVal = new int(r.Val());
        std::cout << "SomeClass copy constructor(pVal = 0x" << std::hex << pVal << std::dec << ")" << std::endl;
    }   
    SomeClass(const SomeClass&& r){
        pVal = r.pVal;
        r.pVal = 0;
        std::cout << "SomeClass move constructor(pVal = 0x" << std::hex << pVal << std::dec << ")" << std::endl;
    }
    ~SomeClass(){
        if(pVal)
            delete pVal;
        std::cout << "SomeClass destructor(pVal = 0x" << std::hex << pVal << std::dec << ")" << std::endl;
    }
};

class OtherClass{
    SomeClass sc;
public:
    OtherClass(int val):sc(val){
    }

Not bu secion:

#if 1
    OtherClass(SomeClass r):sc(std::move(r)){
    }
#else
    OtherClass(const SomeClass& r):sc(r){
    }   
    OtherClass(const SomeClass&& r):sc(std::move(r)){
    }
#endif

...

    int Val(){ return sc.Val(); }
    ~OtherClass(){
    }
};

#define ECHO(expr)  std::cout << std::endl << "line " << __LINE__ << ":\t" #expr ":" << std::endl; expr

int _tmain(int argc, _TCHAR* argv[])
{
    volatile int __dummy = 0;
    ECHO(SomeClass o(10));

    ECHO(OtherClass oo1(o));            
    __dummy  = oo1.Val();
    ECHO(OtherClass oo2(std::move(o))); 
    __dummy  = oo2.Val();
    ECHO(OtherClass oo3(SomeClass(20)));  
    __dummy  = oo3.Val();

    ECHO(std::cout << __dummy << std::endl);
    ECHO(return 0);
}

Sizin de belirttiğiniz gibi, bana iki yaklaşımı test etmek için izin veren bir derleme zamanı bir geçiş var.

Şimdi, bu sonuçları görmek için zaman.

Sonuçları en iyi görüntülenen metin modu karşılaştırın, solda görebilirsiniz #if 1 derleme, yani biz onay önerilen geçici çözüm, ve sağ #if 0, yani biz onay "koşer" şekilde tanımlanan c 0 x! alt text

Yanlış derleyici aptalca şeyler yapar, Ben şüphe, üçüncü test için fazladan hareket kurucu kurtardı.

Ama dürüst olmak gerekirse, biz başka bir hesap için iki yıkıcı olarak önerilen geçici çözüm, ama bu kesinlikle bir küçük dezavantajı da göz önünde bulundurularak hiçbir eylemler gerçekleştirilmelidir eğer bir hareket oluştu nesneyi tahrip ediliyor. Yine de, iyi biliyorum.

Herhangi bir durumda, daha kapsayıcı bir sınıf bir diğer kurucu okuma nokta bırakmıyorum. Tüm sıkıcı iş zaten SomeClass bu yapılır beri sadece birkaç satır meselesivardırbir hareket için kurucu.

İlginç bir konu için teşekkürler! Saygılar, Leonid.

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

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • movies95

    movies95

    27 Kasım 2006
  • Peyton

    Peyton

    28 Aralık 2008
  • ŠĩŗĜŕôŵåɭȍҭҭ

    ŠĩŗĜŕô

    29 Kasım 2009