2013-05-25 4 views
1

Le code ci-dessous:Concaténer deux chaînes déplacé

#include <iostream> 
#include <string> 
using namespace std; 

int main() { 
    string s1 = "hello"; 
    string s2 = "my"; 
    string s3 = "world"; 
    string s4; 
    s4 = move(s1) + move(s2) + move(s3); 
    cout << "s4(" << s4 << ") = s1(" << s1 << ") + s2(" << s2 << ") + s3(" << s3 << ")"<< endl; 
} 

donne le résultat suivant:

s4(hellomyworld) = s1() + s2(my) + s3(world) 

Pouvez-vous expliquer ce qui se passe? (Testé avec XCode 4.6.1)

EDIT: Je devrait voir s4(hellomyworld) = s1() + s2() + s3()

+0

Veuillez vous habituer à décrire ce que vous attendiez de la place. Votre compréhension peut ne pas être la même que votre compréhension (et, en effet, parce que vous êtes ici en train de poser une question pour résoudre votre confusion, c'est probablement pas!) –

Répondre

4

Je suppose que vous attendiez s4(hellomyworld) = s1() + s2() + s3(). Tout d'abord, le mouvement laisse l'objet source dans "un état valide avec une valeur non spécifiée" ([C++11: 21.4.2/2]) —, c'est-à-dire que vous ne pouvez faire aucune déclaration sur la valeur d'une chaîne après son déplacement.

Deuxièmement, std::move est un abus de langage, en ce que il ne déplace réellement rien. Le mouvement est implémenté en échangeant des choses, et il n'y a aucune garantie que votre string operator+ fasse quoi que ce soit (voir la réponse de jmihalicza pour un exemple d'implémentation); tout std::move fait est d'obtenir une référence rvalue que peut être déplacé à partir de.

[C++11: 21.4.6.3/1] dit à propos std::basic_string& assign(basic_string&& str) noexcept (ce qui est la fonction que vous êtes vraiment invoquer, lorsque vous suivez toutes les miettes de pain de operator+) que « une mise en œuvre est valide swap(str) », mais cela ne signifie pas un swap a de se produire .

1

s4 = move(s1) + move(s2) + move(s3) est en fait operator=(s4, operator+(operator+(move(s1), move(s2)), move(s3)); La mise en œuvre de operator+ n'est pas nécessaire de modifier son argument rvalue, mais est autorisé. On peut supposer que l'implémentation est quelque chose comme ceci:

string operator+(string&& left, string&& right) 
{ 
    string result(left); 
    return result += right; 
} 

où le droit est seulement lu.

+0

Pourquoi voudriez-vous créer une variable temporaire 'result' si vous allez retourner une référence? (Notez que la norme ne renvoie pas de référence là-bas) –

+0

Merci pour la correction, je fixe l'extrait de code – jmihalicza

+0

Hmm, si je ne me trompe pas, votre nouvelle version copie empêche élision ... –

0
template<class _CharT, class _Traits, class _Allocator> 
_LIBCPP_INLINE_VISIBILITY inline 
basic_string<_CharT, _Traits, _Allocator> 
operator+(basic_string<_CharT, _Traits, _Allocator>&& __lhs, basic_string<_CharT, _Traits, _Allocator>&& __rhs) 
{ 
    return _VSTD::move(__lhs.append(__rhs)); 
} 

semble donc comme lors de la concaténation __rhs s sont restés inchangés. Après que toute la chaîne a été accumulée à s1, l'affectation de déplacement de s4 a été vidée s1.

Questions connexes