3

以下测试在 g++ 4.8.1 中编译

int main()
{
    vector<string> v ;
    v.push_back("33333") ;
    v.push_back("44444") ;
    v.push_back("55555") ;

    {
        string x("xxxxx") ;
        v.push_back(x) ; //copy 
        cout << "x=" << x << endl ; //x=xxxxx
    } //checkpoint1

    {
        string y("yyyyy") ;
        v.push_back(std::move(y)) ; //move 
        cout << "y=" << y << endl ; //y=
    } //checkpoint2

    for(auto const i : v)
        cout << i << " " ; 
    cout << endl ; //33333 44444 55555 xxxxx yyyyy 
}

这是一个非常简单的来源,我的测试重点是std::move. 如您所见,string x是本地 var,而 executev.push_back(x)x复制到 vector v,所以x仍然有"xxxxx"after push_back。在 checkpoint1 之后,x它就消失了(它只是本地的)但是向量v有它的值,因为x在做的时候被复制了v.push_back(x),所以没关系!

至于string y,它被移动到向量v,因为std::move被使用,所以你可以看到cout << "y=" << y显示"y=",而不是"y=yyyyy",这是正确的行为。

我没有得到的是,在 checkpoint2 之后,字符串y作为本地 var 已经结束,所以 vectorv作为y所有者(因为y被移动到 vector vpush_back(std::move(y))应该包含一个无效元素y,因为作为堆栈本地 var,生命在 checkpoint2 结束!

我很困惑,在checkpoint2之后,vectorv仍然有"yyyyy"y被移动到vector v,如果vectorv只有一个指针vptr = &y,因为y它是堆栈内存中的本地var,在它的范围之外,堆栈消失了,所以vectorvptr没用,看起来像这样不对!

所以它一定是vector有自己的记忆保存"yyyyy"在自己的,但如果是这样的话,它是一样的push_back(x),那为什么还要麻烦std::move(y)呢?

我错过了什么吗?

4

2 回答 2

3

你可以想像std::string一种智能指针。该std::string变量指向存储在其他地方的实际字符串数据。当你std::moveastd::string时,新字符串会被赋予一个指向该数据的指针,并且旧字符串会被清除。

这是它如何工作的一个非常简单的版本:

class MyString {
  public:
    // Move constructor
    MyString(MyString&& that)
      // Just make our string data point to the other string
      : string_data(that.string_data)
    {
      // And make sure the string we are moving from no longer points
      // to that data so it won't get freed when the other string
      // is destructed.         
      that.string_data = 0;
    }

    // Copy constructor
    MyString(const MyString& that)
      // We can't take the other string's data, so we need a copy
      : string_data(new char[strlen(that.string_data)+1])
    {
      strcpy(string_data,that.string_data);
    }

    // Assignment using copy and swap idiom.
    MyString& operator=(MyString that)
    {
      std::swap(string_data,that.string_data);
      return *this;
    }

    ~MyString()
    {
      // string_data may be null if it has been moved from, but
      // that's ok -- it is safe to delete a null pointer.
      delete [] string_data;
    }

  private:
    char *string_data;
};

当你移动y到向量中时。字符串数据现在是向量所拥有的字符串的一部分,y不再与它有任何关系。当y超出范围时,它对向量中的数据没有影响,因为y不再有指向它的指针。

于 2013-07-04T01:53:27.273 回答
0

移动构造函数,就像复制构造函数一样,涉及两个对象: (a) 原始源对象;(b) 新创建的目标对象。

在您的情况下,局部变量是源对象,而目标对象是新创建的对象,push_back该对象被放置在向量存储中。

移动构造函数和复制构造函数之间的区别在于,按照惯例,源对象可能会被修改,并且不会被再次使用(源对象是“过期”对象)。这允许类作者进行可能损坏源对象的优化,例如将资源从源对象转移(“移动”)到目标对象。

在 的情况下std::string,可能每个字符串都包含一个指向动态分配数组的成员指针。移动构造函数可以简单地将指针从源对象交换到目标对象。

于 2013-07-04T12:59:42.990 回答