I'm confused about how scoping and memory persistence works with std::vectors. Consider the following:
#include <string>
#include <vector>
class Entity
{
std::string name;
}
class MyClass
{
std::vector<Entity> class_vec;
MyClass()
{
std::vector<Entity> local_vec(100);
class_vec = local_vec;
}
}
int main(argc, char* argv[])
{
MyClass myclass;
}
If the vector elements are copy by value everything should be OK but if they use move for example, bad things can happen as local_vec will go out of scope. From what I understand local_vec is created on the stack and when the constructor is exited should be removed from it.
In the documentation it says "move is used when assigning vectors when possible" - isn't this asking for problems? When do I need to be worried about a vector assigned to another vector will have its elements go out of scope if they have been created in a certain scope?
A for sure way to cause a problem is if a vector of pointers are used to reference stack objects but that isn't being done here.
That's not correct. There would be no problem with move semantics in this situation. That being said, the compiler would not be permitted to apply them, so we get a copy.
We have two named vectors:
class_vecandlocal_vec. Both are lvalue references, so we get the copy assignment operator.So, at least at a glance, C++ must call the copy assignment operator. Now, aggressive optimization and inlining might help with that, but it can't simply decide it wants to call a different overload.
That being said, we can force move semantics here with
std::move, which turns an lvalue reference into an rvalue reference, communicating to the compiler that we don't plan to use the value after this fact.Now we've got a move assignment operator. And this still isn't a problem. In fact, it's probably an improvement. If we assume
std::vectoris defined something like thisThen the move assignment operator would look something like this.
That is, when we're done,
thispoints to all of our data andthatpoints to nothing. It's left in a valid but unspecified state (in this example, pointing tonullptr), so that it can be safely destructed without damaging anything else, and certainly without damaging the original data.