Std :: move ve std :: forward arasındaki fark nedir


160

Bunu burada gördüm: Base-class Move Constructor'ı çağıran Move Constructor

Birisi açıklayabilir mi:

  1. std::moveve std::forwardtercihen bazı kod örnekleri arasındaki fark nedir?
  2. Kolayca nasıl düşünülür ve ne zaman kullanılır


"Kolayca düşünmeye ve ne zaman hangi nasıl kullanılır" Sen kullanmak moveistediğiniz zaman hareket bir değeri ve forwardmükemmel yönlendirmeyi kullanmak istediğinizde. Bu roket bilimi değil;)
Nicol Bolas

move () koşulsuz yayın gerçekleştirir, burada forward () iletilen parametreye göre yayın yapar.
RaGa__M

Yanıtlar:


159

std::movebir nesneyi alır ve ona geçici (bir değer) olarak davranmanızı sağlar. Anlamsal bir gereklilik olmamakla birlikte, genellikle bir rvalue referansını kabul eden bir işlev, onu geçersiz kılar. Gördüğünüzde std::move, nesnenin değerinin daha sonra kullanılmaması gerektiğini gösterir, ancak yine de yeni bir değer atayabilir ve kullanmaya devam edebilirsiniz.

std::forwardtek kullanımlık bir duruma sahiptir: geçici bir işlev parametresini (işlevin içinde), arayanın iletmek için kullandığı değer kategorisine (değer veya rvalue) atamak. Bu, rvalue argümanlarının rvalue olarak iletilmesine ve lvalues ​​lvalues ​​olarak iletilmesine izin verir, bu da "mükemmel yönlendirme" adı verilen bir şemadır.

To göstermektedir :

void overloaded( int const &arg ) { std::cout << "by lvalue\n"; }
void overloaded( int && arg ) { std::cout << "by rvalue\n"; }

template< typename t >
/* "t &&" with "t" being template param is special, and  adjusts "t" to be
   (for example) "int &" or non-ref "int" so std::forward knows what to do. */
void forwarding( t && arg ) {
    std::cout << "via std::forward: ";
    overloaded( std::forward< t >( arg ) );
    std::cout << "via std::move: ";
    overloaded( std::move( arg ) ); // conceptually this would invalidate arg
    std::cout << "by simple passing: ";
    overloaded( arg );
}

int main() {
    std::cout << "initial caller passes rvalue:\n";
    forwarding( 5 );
    std::cout << "initial caller passes lvalue:\n";
    int x = 5;
    forwarding( x );
}

Howard'ın bahsettiği gibi, her iki fonksiyon da sadece referans tipine atıldığından benzerlikler de vardır. Ancak bu özel kullanım durumlarının dışında (rvalue referans dökümlerinin kullanışlılığının% 99,9'unu kapsar), static_castdoğrudan kullanmalı ve ne yaptığınıza dair iyi bir açıklama yazmalısınız.


Ben emin tam olarak öyle değilim std::forwardbireyin tek kullanım durumunda işlev argümanları mükemmel yönlendirme olduğunu. Nesne üyeleri gibi diğer şeyleri mükemmel bir şekilde iletmek istediğim durumlarla karşılaştım.
Geoff Romer

@GeoffRomer Bir parametrenin üyeleri? Bir örnek var mı?
Potatoswatter

Ayrı bir soru olarak bir örnek gönderdim: stackoverflow.com/questions/20616958/…
Geoff Romer

Hmm, bu yüzden bunu doğru anlarsam, forward (5) 'in 5 üzerinde çalıştığı yerde forward (x)' in x 'i x' de geçtiğim gibi bir aşırı yük yazmak zorunda kalmadan başvuru.
iheanyi

@iheanyi Evet, fikir bu! Ancak bu sadece sıradan bir işlev değil, bir şablon olmalıdır.
Potatoswatter

63

Hem std::forwardve std::movebaşka bir şey yayınları bulunmaktadır.

X x;
std::move(x);

Yukarıda xX tipi lvalue ifadesi X tipi bir rvalue ifadesine (tam olarak bir xvalue) verilir. moveayrıca bir rvalue kabul edebilir:

std::move(make_X());

ve bu durumda bir kimlik fonksiyonudur: X tipi bir değer alır ve X tipi bir değer döndürür.

İle std::forwardhedefi bir dereceye kadar seçebilirsiniz:

X x;
std::forward<Y>(x);

xX türünün lvalue ifadesini Y türündeki bir ifadeye çevirir . Y'nin ne olabileceği konusunda kısıtlamalar vardır.

Y erişilebilir bir X Tabanı veya X Tabanı referansı olabilir. Y X veya X referansı olabilir. forward . Y, erişilebilir bir Taban dönüşümü dışında X'ten dönüştürülebilen bir tür olamaz.

Y bir değer değeri referansıysa, sonuç bir değer değeri ifadesi olacaktır. Y bir değer değeri başvurusu değilse, sonuç bir değer (kesin olacak x değeri) ifadesi olur.

forwardrvalue bağımsız değişkenini yalnızca Y bir lvalue referansı değilse alabilir. Yani, değer için bir değer atayamazsınız. Bu, güvenlik nedenlerinden ötürü yaygın bir şekilde yapılması, sallanan referanslara yol açmaktadır. Ancak bir rvalue'yu rvalue'ya dökmek tamamdır ve izin verilir.

İzin verilmeyen bir şeye Y belirtmeye çalışırsanız, hata çalışma zamanında değil derleme zamanında yakalanır.


Bir nesneyi kullanarak bir işleve mükemmel şekilde iletirsem std::forward, o işlev yürütüldükten sonra, o nesneyi kullanabilir miyim? std::moveDurumun tanımsız bir davranış olduğunun farkındayım .
iammilind

1
İlgili olarak move: stackoverflow.com/a/7028318/576911 Çünkü forward, bir değer girerseniz, API'niz bir değer alıyormuş gibi tepki vermelidir. Normalde bu, değerin değiştirilmeyeceği anlamına gelir. Ancak, sabit olmayan bir değerse, API'nız bunu değiştirmiş olabilir. Bir rvalue iletirseniz, bu normalde API'nızın ondan taşınmış olabileceği ve böylece stackoverflow.com/a/7028318/576911 geçerli olacağı anlamına gelir .
Howard Hinnant

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.