Aracılığıyla paylaş


Rvalue başvuru Bildiricisi: & &

Rvalue deyim bir başvuru bulunur.

type-id && cast-expression

Notlar

Rvalue başvurular bir lvalue bir rvalue ayırt etmek etkinleştirin. Lvalue başvuruları ve rvalue başvurular sözdizimsel olarak ve anlam olarak benzer, ancak bunlar biraz farklı kurallara uyar. Lvalues ve rvalues hakkında daha fazla bilgi için bkz: Lvalues ve Rvalues. Lvalue başvurular hakkında daha fazla bilgi için bkz: Lvalue başvuru Bildiricisi: &.

Rvalue başvurular uygulaması nasıl destek aşağıdaki bölümlerde açıklanmıştır semantiği Taşı ve kusursuz iletme.

Taşıma semantiği

Rvalue başvurular destek uygulaması semantiği Taşı, kendisi önemli ölçüde artırmak uygulamalarınızın performansını. Semantiği kaynaklar (örneğin, dinamik olarak ayrılan bellek) aktarır kod yazmanızı sağlayan bir nesneden diğerine taşıyın. Semantics çalışır programda başka bir yerde başvurulamaz geçici nesnelerinden aktarılacak kaynaklar sağlar çünkü taşıyın.

Taşıma semantiği uygulamak için normal olarak verdiğiniz bir yapıcı, taşıma ve isteğe bağlı olarak bir taşı atama işleci (operator=), sınıfınız için. Kopyala ve atama işlemleri, kaynakları olan rvalues sonra otomatik olarak yararlanmak semantiği taşıyın. Varsayılan kopya kurucu, derleyici varsayılan taşıma kurucu sağlamaz. Bir taşı kurucu ve uygulamanızda kullanmak hakkında daha fazla bilgi için bkz: Nasıl yapılır: taşıma kurucu yazma.

Sıradan işlevlerin aşırı yüklenebilir ve avantajlarından yararlanmak için işleçler semantiği taşıyın. Visual C++ 2010Standart şablon kitaplığı (stl) halinde taşıma semantiği tanıtır. Örneğin, string sınıfı taşıma semantiği gerçekleştirmek işlemlerini gerçekleştirir. Birkaç dizesini birleştirir ve sonucu yazdırır, aþaðýdaki örneði ele alalým:

// string_concatenation.cpp
// compile with: /EHsc
#include <iostream>
#include <string>
using namespace std;

int main()
{
   string s = string("h") + "e" + "ll" + "o";
   cout << s << endl;
}

Önce Visual C++ 2010, yapılan her çağrı operator+ ayırır ve yeni geçici döndüren string nesne (rvalue). operator+kaynak dizeleri lvalues veya rvalues olduğunu bilmez çünkü bir dize için diğer eklenemiyor. Kaynak dizeleri hem de lvalues, programda başka bir yerde başvurulan ve bu nedenle değiştirilmemesi gerekir. Rvalue başvurular kullanarak operator+ programda başka bir yerde başvurulamaz rvalues yararlanmak için değiştirilebilir. Bu nedenle, operator+ şimdi bir dize diğerine ekleyebilir. Bu dinamik bellek ayırma sayısını önemli ölçüde azaltabilir, string class gerekir gerçekleştirmek. string sınıfı hakkında daha fazla bilgi için, bkz. basic_string Class.

Dönüş değeri en iyi duruma getirme (rvo) veya adlandırılmış dönüş değeri en iyi duruma getirme (nrvo) derleyici kullanamadığınız taşıma semantiği de yardımcı olur. Tür tanımlıyorsa bu gibi durumlarda, derleyici taşıma yapıcısını çağırır. Dönüş değeri iyileştirme adlı hakkında daha fazla bilgi için bkz: adlı dönüş değeri iyileştirme Visual C++ 2005'te.

Taşıma semantiği daha iyi anlamak için bir öğe içine ekleme örneði ele alalým bir vector nesnesi. Yoksa kapasitesi vector nesne aşılırsa, vector nesne öğelerini bellek tahsis ve sonra her öğe eklenen öðe için yer açmak için başka bir bellek konumuna kopyalayın. Ekleme işlemi bir öğe kopyalarken, yeni bir öğe oluşturur, önceki öğeden yeni bir öğe için verileri kopyalamak için Kopyala yapıcısını çağırır ve önceki öğe yok eder. Taşıma semantiği doğrudan kopyalama işlemlerini ve pahalı bellek ayırması gerçekleştirmek zorunda kalmadan nesneleri taşımak etkinleştirir.

İçinde hareket semantiği yararlanmak için vector Örneğin, verileri bir nesneden diğerine taşımak için Taşı yapıcı yazabilirler.

Taşıma semantiği giriş stl içine hakkında daha fazla bilgi için Visual C++ 2010, bkz: Standart C++ Kitaplık Başvurusu.

Kusursuz iletme

Kusursuz iletme aþýrý yüklenmiþ işlevleri gereksinimini azaltır ve iletme sorun yardımcı kaçının. Sorun iletme başvuru parametreleri olarak yapacağı genel fonksiyon yazmak ve geçirir oluşabilir (ya da ileten) başka bir işlev için bu parametreler. Örneğin, generic işlev türünde bir parametre alır const T&, sonra da çağrılan işlev bu parametrenin değerini değiştiremezsiniz. Genel işlevin türünde bir parametre alırsa T&, sonra da bir rvalue (geçici bir nesne veya tamsayı literal) kullanarak işlevi çağrılamaz.

Normalde, bu sorunu çözmek için her ikisi de ele genel işlevi ın aşırı yüklü sürümlerini sağlamanız gereken T& ve const T& her birinin kendi parametreleri. Sonuç olarak, aşırı yüklü işlevleri sayısı üssel parametre sayısı artar. Rvalue başvurular rasgele bağımsız değişkenleri kabul eden ve diğer işlevi doğrudan çağırıldıktan sanki başka bir işleve iletir işlevi bir sürümünü yazmanızı sağlar.

Dört tür bildirir aþaðýdaki örneði ele alalým W, X, Y, ve Z. Kurucu her türü için farklı bir birleşimi götüren const ve olmayan-const lvalue başvuru parametreleri olarak.

struct W
{
   W(int&, int&) {}
};

struct X
{
   X(const int&, int&) {}
};

struct Y
{
   Y(int&, const int&) {}
};

struct Z
{
   Z(const int&, const int&) {}
};

Nesneleri oluşturan genel fonksiyon yazmak istediğinizi varsayalım. Aşağıdaki örnekte, bu işlev yazmanın bir yolu gösterilmektedir:

template <typename T, typename A1, typename A2>
T* factory(A1& a1, A2& a2)
{
   return new T(a1, a2);
}

Aşağıdaki örnek, geçerli bir arama gösterir factory işlevi:

int a = 4, b = 5;
W* pw = factory<W>(a, b);

Ancak, aşağıdaki örnek geçerli bir çağrı yok factory çünkü işlev factory parametrelerinin, ancak düzenlenerek sürer lvalue başvuruları rvalues kullanılarak adlandırılır:

Z* pz = factory<Z>(2, 2);

Normalde, bu sorunu çözmek için aşırı yüklü bir sürümü oluşturmalısınız factory işlevi her birleşimi için A& ve const A& parametreleri. Rvalue başvuruları etkinleştirmek bir sürümünü yazmanızı factory , aşağıdaki örnekte gösterildiği gibi işlev:

template <typename T, typename A1, typename A2>
T* factory(A1&& a1, A2&& a2)
{
   return new T(std::forward<A1>(a1), std::forward<A2>(a2));
}

Bu örnek için parametre olarak rvalue başvurular kullanan factory işlevi. Amacı, std::forward işlevidir Fabrika işlevi şablon sınıfının yapıcısına Parametreler iletmek için.

Aşağıdaki örnekte gösterildiği main düzenlenen kullanır işlev factory örneklerini oluşturmak için işlev W, X, Y, ve Z sınıfları. Yeniden düzenlenen factory işlevi parametreleri (lvalues veya rvalues) uygun sınıfı yapıcısına iletir.

int main()
{
   int a = 4, b = 5;
   W* pw = factory<W>(a, b);
   X* px = factory<X>(2, b);
   Y* py = factory<Y>(a, 2);
   Z* pz = factory<Z>(2, 2);

   delete pw;
   delete px;
   delete py;
   delete pz;
}

Rvalue başvurular ek özellikler

Lvalue başvuru ve rvalue referans almak üzere bir işlev aşırı yüklenmeye neden olabilir.

Tarafından gerçekleştirilecek işlevlerin aşırı bir const lvalue başvuru veya rvalue referans, yazabileceğiniz düzenlenerek olmayan nesneler (lvalues) arasında ayıran kodu ve değiştirilebilir geçici değerler (rvalues). Nesne olarak işaretli değilse rvalue başvuru geçen bir işlev için bir nesne geçirmek const. Fonksiyonunu aşağıdaki örnekte gösterildiği f, aşırı hangi yüklü lvalue başvuru ve rvalue başvuru gerçekleştirilecek. main İşlev çağrıları f lvalues ve bir rvalue.

// reference-overload.cpp
// Compile with: /EHsc
#include <iostream>
using namespace std;

// A class that contains a memory resource.
class MemoryBlock
{
   // TODO: Add resources for the class here.
};

void f(const MemoryBlock&)
{
   cout << "In f(const MemoryBlock&). This version cannot modify the parameter." << endl;
}

void f(MemoryBlock&&)
{
   cout << "In f(MemoryBlock&&). This version can modify the parameter." << endl;
}

int main()
{
   MemoryBlock block;
   f(block);
   f(MemoryBlock());
}

Bu örnek aşağıdaki çıktıyı üretir:

In f(const MemoryBlock&). This version cannot modify the parameter.
In f(MemoryBlock&&). This version can modify the parameter.

Bu örnekte, ilk arama f argüman bir yerel değişken (lvalue) geçirir. İkinci çağrı f geçici bir nesne, baðýmsýz deðiþken olarak geçirir. Geçici nesnesi programda başka bir yerde başvurulamaz çünkü çağrı aşırı yüklü sürümüne bağlar f nesneyi değiştirmek ücretsiz bir rvalue referans alır.

Derleyici bir lvalue olarak adlandırılan rvalue başvuru ve adsız rvalue başvuru bir rvalue davranır.

Bu parametre, parametre olarak bir rvalue başvuru geçen bir işlev yazdığınızda, işlev gövdesinde bir lvalue olarak kabul edilir. Bir programın çeşitli bölümleri tarafından adlandırılmış bir nesneye başvurulabilir çünkü derleyici bir lvalue adlandırılmış rvalue başvuru değerlendirir; bir programı değiştirmek veya kaynakları bu nesneden kaldırmak için birden fazla bölümü izin vermek tehlikeli olabilir. Örneğin, bir programın birden çok bölüm aynı nesneden kaynak aktarmaya çalışırsanız, yalnızca ilk bölümünü başarıyla kaynak aktarın.

Fonksiyonunu aşağıdaki örnekte gösterildiği g, aşırı hangi yüklü lvalue başvuru ve rvalue başvuru gerçekleştirilecek. İşlev f rvalue başvuru parametresi (adlandırılmış rvalue başvuru) olarak alır ve rvalue başvuru (adsız rvalue başvuru) döndürür. Yapılan çağrıda g karşı f, aşırı yükleme çözümü sürümünü seçer g , geçen lvalue başvuru olduğundan gövdesi f onun parametresi bir lvalue değerlendirir. Yapılan çağrıda g karşı main, aşırı yükleme çözümü sürümünü seçer g , geçen rvalue başvuru olduğundan f rvalue başvurusunu verir.

// named-reference.cpp
// Compile with: /EHsc
#include <iostream>
using namespace std;

// A class that contains a memory resource.
class MemoryBlock
{
   // TODO: Add resources for the class here.
};

void g(const MemoryBlock&) 
{
   cout << "In g(const MemoryBlock&)." << endl;
}

void g(MemoryBlock&&) 
{
   cout << "In g(MemoryBlock&&)." << endl;
}

MemoryBlock&& f(MemoryBlock&& block)
{
   g(block);
   return block;
}

int main()
{
   g(f(MemoryBlock()));
}

Bu örnek aşağıdaki çıktıyı üretir:

In g(const MemoryBlock&).
In g(MemoryBlock&&).

Bu örnekte, main işlevi geçirmeden bir rvalue f. Gövdesi f , adlandırılmış parametre bir lvalue değerlendirir. Çağrısından f için g lvalue referansı parametre bağlar (ilk aşırı yüklü sürümü g).

  • Rvalue başvurusu için bir lvalue çevirebilirsiniz.

stl std::move işlevi rvalue bir nesne referansı için bir nesneyi dönüştürmek etkinleştirir. Alternatif olarak, kullanmak static_cast aşağıdaki örnekte gösterildiği gibi bir rvalue başvurusu için bir lvalue atama yapmak için anahtar sözcük:

// cast-reference.cpp
// Compile with: /EHsc
#include <iostream>
using namespace std;

// A class that contains a memory resource.
class MemoryBlock
{
   // TODO: Add resources for the class here.
};

void g(const MemoryBlock&) 
{
   cout << "In g(const MemoryBlock&)." << endl;
}

void g(MemoryBlock&&) 
{
   cout << "In g(MemoryBlock&&)." << endl;
}

int main()
{
   MemoryBlock block;
   g(block);
   g(static_cast<MemoryBlock&&>(block));
}

Bu örnek aşağıdaki çıktıyı üretir:

In g(const MemoryBlock&).
In g(MemoryBlock&&).

 

İşlev şablonları kendi şablon bağımsız değişken türleri temizlemeniz ve kuralları daraltma başvuru kullanın.

Geçen bir işlev şablon Yaz yaygındır (veya ileten) başka bir işlev parametreleri. Rvalue başvurularını ele işlev şablonları için şablon türü kesintinin nasıl çalıştığını anlamak önemlidir.

İşlev bağımsız değişkeni bir rvalue ise, derleyici rvalue başvurusu bağımsız değişkeni deduces. Örneğin, bir rvalue başvuru türünde bir nesne geçirmek X türü götüren bir şablon işlevi T&& şablon değişkenini kesintinin onun parametresi olarak deduces T olarak X. Bu nedenle, parametre türüne sahip X&&. İşlev bağımsız değişkeni bir lvalue ise veya const lvalue, derleyici lvalue başvurusu türü deduces veya const lvalue başvuru türü.

Aşağıdaki örnek bir yapı şablon bildirir ve daha sonra çeşitli başvuru tipleri için uzmanlaşmış. print_type_and_value İşlevi bir rvalue başvurusu, parametre olarak alır ve uygun özelleştirilmiş sürümünü için ileten S::print yöntemi. main İşlevini çağırmak için çeşitli yolları gösterilmiştir S::print yöntemi.

// template-type-deduction.cpp
// Compile with: /EHsc
#include <iostream>
#include <string>
using namespace std;

template<typename T> struct S;

// The following structures specialize S by 
// lvalue reference (T&), const lvalue reference (const T&), 
// rvalue reference (T&&), and const rvalue reference (const T&&).
// Each structure provides a print method that prints the type of 
// the structure and its parameter.

template<typename T> struct S<T&> {
   static void print(T& t)
   {
      cout << "print<T&>: " << t << endl;
   }
};

template<typename T> struct S<const T&> {
   static void print(const T& t)
   {
      cout << "print<const T&>: " << t << endl;
   }
};

template<typename T> struct S<T&&> {
   static void print(T&& t)
   {
      cout << "print<T&&>: " << t << endl;
   }
};

template<typename T> struct S<const T&&> {
   static void print(const T&& t)
   {
      cout << "print<const T&&>: " << t << endl;
   }
};

// This function forwards its parameter to a specialized
// version of the S type.
template <typename T> void print_type_and_value(T&& t) 
{
   S<T&&>::print(std::forward<T>(t));
}

// This function returns the constant string "fourth".
const string fourth() { return string("fourth"); }

int main()
{
   // The following call resolves to:
   // print_type_and_value<string&>(string& && t)
   // Which collapses to:
   // print_type_and_value<string&>(string& t)
   string s1("first");
   print_type_and_value(s1); 

   // The following call resolves to:
   // print_type_and_value<const string&>(const string& && t)
   // Which collapses to:
   // print_type_and_value<const string&>(const string& t)
   const string s2("second");
   print_type_and_value(s2);

   // The following call resolves to:
   // print_type_and_value<string&&>(string&& t)
   print_type_and_value(string("third"));

   // The following call resolves to:
   // print_type_and_value<const string&&>(const string&& t)
   print_type_and_value(fourth());
}

Bu örnek aşağıdaki çıktıyı üretir:

print<T&>: first
print<const T&>: second
print<T&&>: third
print<const T&&>: fourth

Her çağrının çözmek için print_type_and_value işlevi, derleyicinin ilk şablon değişkenini kesintinin gerçekleştirir. Derleyici başvuru parametre türleri sonucuna varılan şablon değişkenleri değiştirir, kuralları daraltma sonra uygulanır. Örneğin, yerel bir değişken geçirerek s1 için print_type_and_value işlevi aşağıdaki işlevi imzasını üretmek derleyici neden olur:

print_type_and_value<string&>(string& && t)

Derleyici, imza aşağıdaki azaltmak için başvuru kuralları daraltma kullanır:

print_type_and_value<string&>(string& t)

Bu sürümü, print_type_and_value işlevi sonra onun parametresi için doğru özelleştirilmiş sürümünü ileten S::print yöntemi.

Şablon değişkeni türü kesintinin kuralları daraltma başvuru aşağıdaki tabloda özetlenmiştir:

Genişletilmiş tür

Daraltılmış türü

T& &

T&

T& &&

T&

T&& &

T&

T&& &&

T&&

Şablon değişkeni kesintinin kusursuz iletme uygulandığında önemli bir öğedir. Bölümde, bu konunun önceki kısımlarında sunulan, kusursuz iletme, kusursuz iletme daha ayrıntılı açıklanmaktadır.

Özet

Rvalue başvuruları lvalues rvalues ayrım. Bunlar gereksiz bellek ayırma gereksinimini ortadan kaldırarak uygulamalarınızın performansını artırmak ve kopyalama işlemlerini yardımcı olabilir. Bunlar ayrıca rasgele bağımsız değişkenleri kabul eden ve diğer işlevi doğrudan çağırıldıktan sanki başka bir işleve iletir işlevi bir sürümünü yazmanızı sağlar.

Ayrıca bkz.

Görevler

Nasıl yapılır: taşıma kurucu yazma

Başvuru

Tekli operatörler ifadelerle

Lvalue başvuru Bildiricisi: &

Lvalues ve Rvalues

move

forward

Diğer Kaynaklar

Standart C++ Kitaplık Başvurusu