2016-01-14 5 views
2

Je le code suivant:C++ 11 lvalue, rvalue et std :: move()

#include <iostream> 
using namespace std; 
void test(int& a) { 
    cout << "lvalue." << endl; 
} 
void test(int&& a) { 
    cout << "rvalue" << endl; 
} 
int main(int argc, char *argv[]) { 
    int a = 1; 
    int&& b = 2; 
    test(a); 
    test(1); 
    test(std::move(a)); 
    test(b); 
} 

qui délivre:

lvalue. 
rvalue 
lvalue. 
lvalue. 

std::move() et int&& sont des références rvalue, je me demande pourquoi test(std::move(a)) et test(b) sortie lvalue? Est-ce lié à l'appariement de signature et à la surcharge de fonction?

+9

Quel compilateur utilisez-vous? La sortie devrait être 'lvalue rvalue rvalue lvalue'. – TartanLlama

+0

@TartanLlama Je suppose que MSVC, qui est toujours bogué. – Lingxi

+0

@TartanLlama, j'utilise Mac, le compilateur devrait être le clang de LLVM. –

Répondre

5

La sortie doit être:

lvalue. 
rvalue 
rvalue 
lvalue. 

Il y a une distinction très importante à faire entre les expressions qui sont rvalues ​​et expressions dont le type est une référence rvalue. Le type de b est une référence rvalue à int, mais l'expression b est une valeur lvalue; c'est une variable, vous pouvez prendre son adresse. C'est pourquoi la dernière ligne de sortie est lvalue plutôt que rvalue. Pour changer un rvalue, vous devez appeler std::move sur elle:

test(std::move(b)); 
+0

Cool, tu as raison.L'EDI que j'ai utilisé ignore l'option "-std = C++ 11" avec la commande sous-jacente, de sorte que ma sortie ressemble à ce que j'ai posté. J'ai testé le code dans Terminal, s'il est compilé sans l'option "-std = C++ 11", alors la sortie non désirée est donnée avec des avertissements. –

1

Vous pouvez lire cet article, ce qui explique très bien Universal References in C++11. Il convient également de mentionner que maintenant ces références appelées références de renvoi.

Dans votre cas, vous avez

void test(int& a); // lvalue reference overload 
void test(int&& a); // rvalue reference overload 

Deuxième cas vous permet d'implémenter la sémantique de déplacer ou le transfert parfait à l'intérieur de la fonction. Bien que le premier le permette également, il vous suffit d'utiliser std::move qui convertira sa valeur en valeur réelle.

test(a); 
test(1); 
test(std::move(a)); 
test(b); 
  • a a un nom, afin d'appliquer la sémantique de mouvement à ce serait tacitement dangereusement confus et sujette à erreur parce que la chose dont nous venons d'emménager, est toujours accessible sur les lignes suivantes de code.

  • 1 n'a pas de nom, vous pouvez prendre l'adresse de celui-ci, il s'agit donc d'une valeur. En utilisant std::move en utilisant std::move, vous devez activer cette valeur pour la valeur rvalue, vous devez vous en souvenir lorsque vous utilisez a la prochaine fois.

  • b la même chose que pour a - il a un nom, vous pouvez prendre l'adresse de celui-ci.

Quelques exemples de lvalues ​​et rvalues:

// lvalues: 
// 
int i = 42; 
i = 43; // ok, i is an lvalue 
int* p = &i; // ok, i is an lvalue 
int& foo(); 
foo() = 42; // ok, foo() is an lvalue 
int* p1 = &foo(); // ok, foo() is an lvalue 

// rvalues: 
// 
int foobar(); 
int j = 0; 
j = foobar(); // ok, foobar() is an rvalue 
int* p2 = &foobar(); // error, cannot take the address of an rvalue 
j = 42; // ok, 42 is an rvalue 
+0

Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et de fournir le lien pour référence. Les réponses à lien uniquement peuvent devenir invalides si la page liée change. - [De l'avis] (/ review/low-quality-posts/10890990) –

+1

@ Mhd.Tahawi J'ai pris vos conseils à cœur :) – Yola