Rvalue referansıyla döndürme daha verimli mi?


Yanıtlar:


246
Beta_ab&&
Beta::toAB() const {
    return move(Beta_ab(1, 1));
}

Bu, lvalue referans durumunda olduğu gibi sarkan bir referans döndürür. İşlev döndükten sonra, geçici nesne yok edilecektir. Sen dönmelidir Beta_abaşağıdaki gibi, değeriyle

Beta_ab
Beta::toAB() const {
    return Beta_ab(1, 1);
}

Şimdi, geçici bir Beta_abnesneyi işlevin dönüş değerine doğru şekilde taşımaktır . Derleyici yapabilirse, RVO (dönüş değeri optimizasyonu) kullanarak taşınmayı tamamen önleyecektir. Şimdi aşağıdakileri yapabilirsiniz

Beta_ab ab = others.toAB();

Ve yapıyı geçici içine abtaşıyacak veya bir taşıma veya kopyalama yapmayı tamamen ihmal etmek için RVO yapacak. Konuyu ve (N) RVO'nun bununla nasıl etkileşime girdiğini açıklayan BoostCon09 Rvalue References 101'i okumanızı tavsiye ederim .


Bir rvalue referansı döndürme durumunuz diğer durumlarda iyi bir fikir olabilir. getAB()Genellikle geçici olarak başvurduğunuz bir işleve sahip olduğunuzu hayal edin . Rvalue geçicileri için sabit bir değer referansı döndürmesi optimal değildir. Böyle uygulayabilirsin

struct Beta {
  Beta_ab ab;
  Beta_ab const& getAB() const& { return ab; }
  Beta_ab && getAB() && { return move(ab); }
};

Not olduğunu moveçünkü bu durumda, isteğe bağlı değil abyerel bir otomatik ne de geçici rvalue de değildir. Şimdi, ref-niteleyici && ikinci işlevin rvalue geçicilerinde çağrıldığını ve copy yerine aşağıdaki hareketi yaptığını söylüyor

Beta_ab ab = Beta().getAB();

51
Dönüş türü bir r-değeri referansı olduğunda, sarkan referans sorununun otomatik olarak ortadan kalktığını varsaymıştım. Beni ısırmadan önce anladığıma sevindim. Yığın parçalayan böcekler berbat.
deft_code

31
:) Gerçekten, rvalue referansları, lvalue referansları gibi "sadece referanslardır". hiçbir şeyi kopyalamaz veya saklamazlar.
Johannes Schaub -

9
bir üye üzerindeki const & niteleyici basit bir const'den daha fazla ne işe yarar?
galinette


3
@galinette Bunlar ref niteleyicilerdir .
Malcolm

2

Bu olabilir biraz farklı bir bağlamda, örneğin, daha verimli:

template <typename T>
T&& min_(T&& a, T &&b) {
    return std::move(a < b? a: b);
}

int main() {
   const std::string s = min_(std::string("A"), std::string("B"));
   fprintf(stderr, "min: %s\n", s.c_str());
   return 0;
}

İlginç bir gözlem olarak, benim makinemde clang++ -O3yukarıdaki kod için 54, normal için 62 talimat üretiyor std::min. Bununla birlikte, bununla birlikte -O0yukarıdaki kod için 518 talimat üretirken normal için 481 komut üretir std::min.


Cevabınız kafam karıştı. Benzer (belki) bir sürümü denemiş ancak başarısız olmuştu: ideone.com/4GyUbZ Nedenini açıklayabilir misiniz?
Deqing

for(:)Dağıtımı kaldırılmış nesnede geçici nesne referansı kullandınız ve bu nesneyi bütünleştirdiniz. Düzeltme: ideone.com/tQVOal
wonder.mice

3
bu cevap aslında yanlış değil mi? T, T parametresi şablon için && olduğu değil r-değeri referans değil, evrensel bir referans ve bu durum için, we should hep çağrı std :: ileri <T>, değil std :: hareket! Bu cevabın yukarıdaki en çok oy alan cevapla doğrudan çeliştiğinden bahsetmiyorum bile.
xdavidliu

@xdavidliu bu cevap, rvalue ile geri dönüşün nasıl daha verimli olabileceği konusunda uydurma bir örnektir. std::move()sadece konuyu daha net göstermek için açık bir kast olarak kullanılır. Projenize kopyalayıp yapıştıracağınız bir kod değil. En çok oy alan cevapla çelişmez, çünkü fonksiyonun içinde geçici bir nesne yaratılmıştır. Burada döndürülen nesne argümanlardan biridir (geçici nesneler, oluşturuldukları noktayı (sözcüksel olarak) içeren tam ifadeyi değerlendirmenin son adımı olarak yok edilir).
wonder.mice

2
@ wonder.mice sonra lütfen T'yi std :: string ile değiştirin; burada şablon kullanmaya hiç gerek yok ve T & &'yi bir r-değeri referansı olarak kullanmak, sadece şablonlar ve r-değerleri konusunda yeni olan insanların gereksiz yere kafasını karıştıran berbat bir stildir.
xdavidliu
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.