Vassilis
Vassilis

Reputation: 2928

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 <------|

Upvotes: 7

Views: 1937

Answers (3)

Quimby
Quimby

Reputation: 19133

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.

Upvotes: 1

Some programmer dude
Some programmer dude

Reputation: 409216

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.

Upvotes: 11

Sergey
Sergey

Reputation: 8238

It will be clear, if we write semantically equal code without std::vector:

B* pre = new B[2]; // Declare std::vector<B> and allocate some space to make the following line correct

B[0] = 1; // pre.push_back(B(1));
B[1] = 2; // pre.push_back(B(2));

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

Actually, vector move boils down to pointer copying without reallocation. Data which the pointer points at remains in it's place, so addresses of vector elements do not change.

In this code example after the fourth line, both pre and post point to the same data with same address.

std::vector is a wrapper for a pointer to array with some additional functionality. So after doing std::vector<B> post(std::move(pre));, post will contain a pointer with the same value which was in pre.

Upvotes: 0

Related Questions