Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do vector elements preserve their original address after a vector std::move?

As you can see in the output, the objects of the vector pre not only "moved" to the vector post, but also preserved their original address space in memory. What is really going on behind this move? Is this behaviour expected? Say I need to have a separate vector of pointers to these objects, is it safe to assume that after this move the objects will always have their original addresses?

Actually, I have a class containing a vector like this and the vector of pointers I mentioned as members. I have also deleted the copy ctors, and defined the move ones for the class.

#include <iostream>
#include <vector>

struct B {
    int val = 0;   
    B(int aInt) : val(aInt) {  };
};

int main() {

    std::vector<B> pre;

    pre.push_back(B(1));
    pre.push_back(B(2));
    std::cout << "pre-move:\t" << (void*)&pre.at(0) << '\n';
    std::cout << "pre-move:\t" << (void*)&pre.at(1) << '\n';

    std::vector<B> post(std::move(pre));

    std::cout << "post-move:\t" << (void*)&post.at(0) << '\n';
    std::cout << "post-move:\t" << (void*)&post.at(1) << '\n';

    return 0;
}

Output:

pre-move:   0x1d7b150 
pre-move:   0x1d7b154 <------|
post-move:  0x1d7b150        |
post-move:  0x1d7b154 <------|
like image 660
Vassilis Avatar asked Dec 23 '18 15:12

Vassilis


People also ask

How are vector elements stored?

Vector elements are placed in contiguous storage so that they can be accessed and traversed using iterators. In vectors, data is inserted at the end. Inserting at the end takes differential time, as sometimes the array may need to be extended.

How do you move a vector element?

You can't move elements from one vector to another the way you are thinking about; you will always have to erase the element positions from the first vector. If you want to change all the elements from the first vector into the second and vice versa you can use swap.

Does vector preserve order?

Yes; vector entries maintain a consistent position within the vector assuming you don't remove any items.

Does vector have a move constructor?

No. It doesn't call the move constructor. To call move constructor of element you will have to call std::move while pushing to vector itself.


2 Answers

A vector is basically nothing more than a pointer to heap-allocated memory, the current length and the current capacity of the vector.

By "moving" a vector, all you're doing is copying those values, and resetting the values of the moved-from vector.

For the data of the vector, it's basically equivalent to

original_pointer = some_place_in_memory;
new_pointer = original_pointer;   // Copies the *value* of original_pointer
original_pointer = nullptr;

There's no need to allocate new memory and copy the data in the vector.

like image 173
Some programmer dude Avatar answered Oct 05 '22 14:10

Some programmer dude


The whole point of the move operation is to avoid copying the elements, so if they got copied(there is no such thing as truly "moving" the memory) the move would be just a copy.

Vectors are usually implemented as 3 pointers: begin,end and capacity. All point to a dynamically-allocated array. Then moving the vector is just copying those three pointers and so the array and elements just change their owner.

I think it should be safe to assume that pointers to the elements remain valid.

like image 43
Quimby Avatar answered Oct 05 '22 14:10

Quimby