2013-05-10 180 views
2

看看這段代碼:C++ 11字符串賦值運算符

#include <iostream> 
#include <algorithm> 
#include <fstream> 
#include <iterator> 

using namespace std; 

int main() 
{ 
ifstream text("text.txt"); 

istreambuf_iterator<char> iis(text); 
string longest_phrase, _longest; 

while (iis != istreambuf_iterator<char>()) { 
    if (*iis != '.') { 
     _longest.push_back(*iis); 
     ++iis; 
     continue; 
    } 
    if (_longest.size() > longest_phrase.size()) 
     longest_phrase = move(_longest); //I want to move the data of _longest to longest_phrase. Just move! Not to copy! 
    cout << _longest.empty(); //why _longest is not empty?? 
      //_longest.clear(); 
    ++iis; 
} 
text.close(); 
longest_phrase.push_back('.'); 
cout << "longest phrase is " << longest_phrase; 
return 0; 
} 

在文件中最長的短語此代碼搜索。 那麼爲什麼從左值到右值的轉換不起作用?

編輯: 這就是爲什麼我認爲它沒有工作:

class Vector { 
public: 
    Vector(vector<int> &&v): vec(move(v)) {} 
    vector<int> vec; 
}; 

int main() 
{ 
    vector<int> ints(50, 44); 
    Vector obj(move(ints)); 
    cout << ints.empty(); 
    return 0; 
} 

謝謝大家快速和有用的答案!

+0

你如何確定它不起作用? – juanchopanza 2013-05-10 09:39:15

+0

_longest.empty();正在返回假。 但現在我知道通過交換兩個字符串實現的字符串移動賦值操作符。 – yivo 2013-05-10 13:31:28

回答

9

除了移動賦值運算符或移動構造函數的進一步後置條件外,不應對標準庫的移動對象的狀態做出具體假設,除非它是合法狀態指定)。

每所述C++ 11標準第17.6.5.15:在C++標準庫中定義的類型

對象可以由(12.8)被移動。移動操作可能會明確指定或隱式生成 。除非另有規定,否則這些移出的物體應爲 ,並置於有效但未指定的狀態。

此外,第21.4.2/21-23關於basic_string類模板的舉動,賦值運算符不是否被移至由串長度的狀態留任何指定,使得在它調用empty()返回true

調用empty()在這種情況下是合法的,因爲它沒有任何關於調用它的string對象狀態的先決條件;另一方面,你不能對它的回報值是什麼進行假設。

+0

我認爲在物體移動後它總是變空。但正如我所見,這取決於實施。無論如何,謝謝! 然後看一個向量移動的例子(上圖) – yivo 2013-05-10 14:01:48

+0

@Yivo:對,它的確依賴於實現。順便說一句,如果這回答你的問題,請考慮標記答案爲接受(或其他用戶發佈的任何其他答案,你可能更喜歡)。 – 2013-05-10 14:04:03

+0

@Yivo作爲一個具體的實際例子,使用「小字符串優化」的'std :: string'通過保持其內容完整無缺(如果在標準下是合法的,字符串優化允許?)。或者一個容器可以在'move'上「交換」,並且將移動到的容器中的元素的銷燬保留到移動後的容器的銷燬中(也可以在標準下是合法的,這取決於它如何指定 - 對象壽命)。 – Yakk 2013-05-10 17:49:24

1

除了其他人對移動和使用移動的對象之後所說的話,移動並不完全是你想要在這裏做的。你在概念上想要分配的內容_longestlongest_phrase並清除_longest。你說的沒錯,試圖避免複製和重新分配,但你可以通過交換實現,很容易:

if (_longest.size() > longest_phrase.size()) 
{ 
    longest_phrase.clear(); // don't need the old content any more 
    longest_phrase.swap(_longest); //move the data of _longest to longest_phrase 
} 
assert(_longest.empty()); 
+0

爲什麼不將_longest移動到longest_phrase然後清除()_longest?這是更明確的意圖。 – 2013-05-10 13:54:17

+0

是'longest_phrase.swap(_longest);'相當於'longest_phrase = move(_longest);'? – yivo 2013-05-10 14:07:43

+0

@Yivo:不,它不是。它做了你想要的東西(移動內容並將'_longest'保留在定義的狀態中),而'move(_longest)'不會。 – 2013-05-10 14:13:57

3

其他答案已經指出,標準的,你不能依賴於移動操作從字符串對象離開該對象空。

但是,您應該期待比副本更有效的事情發生。肯定會發生的是編譯器的basic_string<>& operator=(basic_string<>&&)(字符串'move assignment')通過交換兩個字符串對象來實現(這正是標準類型的建議:「注意:有效實現是swap(str)。」 )。

g ++顯然是這樣實現了字符串移動賦值。

所以你不需要擔心效率 - 應該沒有不必要的字符串複製。但是,如果要再使用該對象,則需要確保在移動後清除從字符串移出的字符串。

+0

我不知道用這種方式實現的字符串移動賦值操作符。 'string str1 =「text1」;' 'string str2 =「text2」;' 'str1 = move(str2);' 現在str1是text2,str2是text1。 – yivo 2013-05-10 13:55:22