How to improve std::vector parameter passing (move semantics?)

谁说我不能喝 提交于 2019-12-19 08:29:10

问题


It seems that I cannot completely understand move semantics: I want to fill an std::vector (member of a class) from an external function. Currently, I have something like:

void fillVector(MyClass & myclass) {
    std::vector<int> vec;
    /* Filling vec */
    // ...
    myclass.setVector(vec);
}

class MyClass {
    public:
         setVector(const std::vector<int> & v) { v_ = v;}
    private:
         std::vector<int> v_;
};

int main() {
    MyClass myclass;
    fillVector(myclass);
    /* Use myclass.v_ somehow */.
}

I had this code for a long time, and it works fine. Now, I cannot understand how it works since I am asigning a reference to a vector which will be destroyed. My questions are:

  1. How is this code able to work?
  2. What is the best way to implement fillVector and MyClass::setVector()? I think that can be done with move semantics but I cannot figure out how.

Thank you!


回答1:


Why the code works:

The scope of vec is the body of fillVector. Inside this entire scope, vec is perfectly valid. This includes the call to setVector. v (the parameter of setVector) is a reference which binds to vec. The body of setVector copies the contents of the vector vec (accessed as v) into v_. That's an actual copy of data, no reference assignment. Only after setVector ends does fillVector end, at which point vec is destroyed. But it was already copied, so all is well.

How to use move semantics:

You could provide an extra overload of setVector which will take an rvalue reference:

class MyClass {
public:
  // ...
  void setVector(std::vector<int> &&v) { v_ = std::move(v); }
  // ...
};

Then, move vec into setVector:

void fillVector(MyClass & myclass) {
    std::vector<int> vec;
    /* Filling vec */
    // ...
    myclass.setVector(std::move(vec));
}

This will invoke the rvalue overload instead of the lvalue one, and the data will be moved, not copied.

However, perhaps a better interface would be to refactor fillVector so that it returns the vector by value, using move semantics automatically:

std::vector<int> fillVector() {
    std::vector<int> vec;
    /* Filling vec */
    // ...
    return vec;  // Note that a move automatically happens here, or even NRVO
}

int main() {
    MyClass myclass;
    myclass.setVector(fillVector());
    /* Use myclass.v_ somehow */.
}



回答2:


vector::operator= assigns contents, and doesn't just link to existing items. When you do v_ = v, v_ gets a new copy of everything in v. Once v is destroyed, the items in v_ still exist.

An easy way to test this and see this in action is to make changes to one of the items in v_[i] and see then print out both v[i] and v_[i]. They will be different.

I don't see anything wrong with your implementation of setVector and fillVector. Is there something in particular you're trying to achieve?



来源:https://stackoverflow.com/questions/28940012/how-to-improve-stdvector-parameter-passing-move-semantics

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!