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:
fillVector
and MyClass::setVector()
? I think that can be done with move semantics but I cannot figure out how.Thank you!
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 */.
}
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?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With