Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Do vector objects go out of scope when assigned to a class variable?

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?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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.

>Solution :

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.

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.

std::vector<Entity> local_vec(100);
class_vec = local_vec;

We have two named vectors: class_vec and local_vec. Both are lvalue references, so we get the copy assignment operator.

constexpr vector& operator=( const vector& other );

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.

class_vec = std::move(local_vec);

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::vector is defined something like this

// Gross oversimplification
template <typename T>
class vector {
  T* array;
  int size;
};

Then the move assignment operator would look something like this.

// Again, gross oversimplification
template <typename T>
vector<T> vector<T>::operator=(vector<T>&& that) {
  this->array = that.array;
  this->size = that.size;
  that.array = std::nullptr;
  that.size = 0;
}

That is, when we’re done, this points to all of our data and that points to nothing. It’s left in a valid but unspecified state (in this example, pointing to nullptr), so that it can be safely destructed without damaging anything else, and certainly without damaging the original data.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading