Bir rvalue referansı beyan eder (standart teklif dokümanı).
İşte rvalue referanslarına bir giriş .
İşte Microsoft'un standart kitaplık geliştiricilerinden birinin değer referanslarına muhteşem bir bakış .
DİKKAT: MSDN'deki bağlantılı makale ("Rvalue Referansları: VC10, Bölüm 2'deki C ++ 0x Özellikleri) Rvalue referanslarına çok açık bir giriştir, ancak bir zamanlar taslak C ++ 11'de geçerli olan Rvalue referansları hakkında açıklamalar yapar standart, ancak sonuncusu için doğru değil! Özellikle, çeşitli noktalarda değer referanslarının bir zamanlar doğru olan ancak değiştirilen değerlere bağlanabileceğini söylüyor (örneğin int x; int &&rrx = x; artık GCC'de derlenmemektedir) - 13 Temmuz 14: 14
Bir C ++ 03 referansı (şimdi C ++ 11'de lvalue referansı olarak adlandırılır) arasındaki en büyük fark, const olmak zorunda kalmadan geçici gibi bir değere bağlanabilmesidir. Dolayısıyla, bu sözdizimi artık yasaldır:
T&& r = T();
rvalue referansları öncelikle aşağıdakileri sağlar:
Anlambilimi taşı . Artık normal sabit değer referansı yerine bir değer referansı alan bir hareket yapıcı ve hareket atama operatörü tanımlanabilir. Bir taşıma, kaynağı değiştirmeden zorunlu kılmak dışında bir kopya gibi işlev görür; aslında, genellikle taşınan kaynaklara sahip olmayacak şekilde kaynağı değiştirir. Bu, özellikle standart kütüphane uygulamalarında yabancı kopyaları ortadan kaldırmak için mükemmeldir.
Örneğin, bir kopya oluşturucu şöyle görünebilir:
foo(foo const& other)
{
this->length = other.length;
this->ptr = new int[other.length];
copy(other.ptr, other.ptr + other.length, this->ptr);
}
Bu kurucu geçici olarak geçtiyse, kopya gereksiz olacaktır çünkü geçici olanın sadece yok edileceğini biliyoruz; neden geçici olarak tahsis edilen kaynakları kullanmıyorsunuz? C ++ 03'te, geçici geçildiğimizi belirleyemediğimiz için kopyalamayı önlemenin bir yolu yoktur. C ++ 11'de, bir hareket yapıcısını aşırı yükleyebiliriz:
foo(foo&& other)
{
this->length = other.length;
this->ptr = other.ptr;
other.length = 0;
other.ptr = nullptr;
}
Buradaki büyük farka dikkat edin: hareket yapıcı aslında argümanını değiştirir. Bu, geçici olanı inşa edilen nesneye etkili bir şekilde "taşıyacak" ve böylece gereksiz kopyayı ortadan kaldıracaktır.
Taşıma yapıcısı, std::moveişlevler kullanılarak açıkça değer değer referanslarına dönüştürülen geçici dosyalar ve sabit olmayan değer referansları için kullanılır (yalnızca dönüşümü gerçekleştirir). Aşağıdaki kod her ikisi için hareket yapıcı çağırmak f1ve f2:
foo f1((foo())); // Move a temporary into f1; temporary becomes "empty"
foo f2 = std::move(f1); // Move f1 into f2; f1 is now "empty"
Mükemmel yönlendirme . rvalue referansları, şablonlanmış işlevler için bağımsız değişkenleri doğru şekilde iletmemizi sağlar. Örneğin bu fabrika işlevini ele alalım:
template <typename T, typename A1>
std::unique_ptr<T> factory(A1& a1)
{
return std::unique_ptr<T>(new T(a1));
}
Eğer factory<foo>(5)çağırırsak, argüman 'yapıcısı int&bir anahtar kelimeyi ele geçirse bile, değişmez bir 5'e bağlanmaz . Bunun yerine kullanabiliriz , ancak yapıcı argümanını const olmayan referansla alırsa ne olur ? Gerçekten jenerik fabrika işlevini hale getirmek için, üzerinde fabrika aşırı zorunda kalacak ve üzerinde . Fabrika 1 parametre türünü alırsa bu iyi olabilir, ancak her ek parametre türü 2 tarafından ayarlanan gerekli aşırı yükü çarpar. Bu çok hızlı bir şekilde sürdürülemez.foointA1 const&fooA1&A1 const&
rvalue referansları, standart kitaplığın std::forwardlvalue / rvalue başvurularını düzgün şekilde iletebilen bir işlev tanımlamasına izin vererek bu sorunu giderir . Nasıl std::forwardçalıştığı hakkında daha fazla bilgi için bu mükemmel yanıta bakın .
Bu, fabrika fonksiyonunu şu şekilde tanımlamamızı sağlar:
template <typename T, typename A1>
std::unique_ptr<T> factory(A1&& a1)
{
return std::unique_ptr<T>(new T(std::forward<A1>(a1)));
}
Şimdi argümanın rvalue / lvalue-ness değeri, Tyapıcısına aktarıldığında korunur . Bu, eğer fabrika bir değerle çağrılırsa, Tyapıcısına bir değerle çağrılır. Eğer fabrika bir lvalue ile çağrılırsa, Tyapıcı bir lvalue ile çağrılır. Geliştirilmiş fabrika işlevi, özel bir kural nedeniyle çalışır:
İşlev parametresi türü, şablon parametresinin T&&bulunduğu formda Tolduğunda ve işlev bağımsız değişkeni bir tür değeri Aolduğunda, tür A&, şablon bağımsız değişkeninin kesilmesi için kullanılır.
Böylece, biz fabrika kullanabilirsiniz gibi:
auto p1 = factory<foo>(foo()); // calls foo(foo&&)
auto p2 = factory<foo>(*p1); // calls foo(foo const&)
Önemli rvalue referans özellikleri :
- Aşırı yük çözünürlüğü için, değerler değerler değer referanslarına bağlanmayı ve değerler değerler değer referanslarına bağlanmayı tercih eder . Bu nedenle geçiciler neden bir kopya oluşturucu / atama işleci yerine bir taşıma yapıcısı / taşıma atama işleci çağırmayı tercih eder.
- rvalue referansları, örtük bir dönüştürme işleminin sonucu olan rvalue'lara ve geçici programlara dolaylı olarak bağlanır . yani
float f = 0f; int&& i = f;iyi biçimlendirilmiştir, çünkü şamandıra dolaylı olarak int'e dönüştürülebilir; referans, dönüşümün sonucu olan bir geçici olacaktır.
- Adlandırılmış değer referansları değerlerdir. Adsız değer referansları değerlerdir. Bu,
std::moveçağrının neden gerekli olduğunu anlamak için önemlidir :foo&& r = foo(); foo f = std::move(r);