2013-05-10 145 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