Как векторные элементы сохраняют свой первоначальный адрес после вектора std :: move? - PullRequest
0 голосов
/ 23 декабря 2018

Как видно на выходе, объекты вектора pre не только "переместились" в вектор post, но и сохранили свое первоначальное адресное пространство в памяти.Что на самом деле происходит за этим шагом?Ожидается ли такое поведение?Скажем, мне нужно иметь отдельный вектор указателей на эти объекты. Можно ли предположить, что после этого перемещения объекты всегда будут иметь свои первоначальные адреса?

На самом деле, у меня есть класс, содержащий векторкак это и вектор указателей, которые я упомянул в качестве членов.Я также удалил копии копоров и определил их для класса перемещения.

#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;
}

Вывод:

pre-move:   0x1d7b150 
pre-move:   0x1d7b154 <------|
post-move:  0x1d7b150        |
post-move:  0x1d7b154 <------|

Ответы [ 3 ]

0 голосов
/ 23 декабря 2018

Вектор - это не что иное, как указатель на выделенную кучу память, текущую длину и текущую емкость вектора.

"Перемещая" вектор, все, что вы делаете, это копируете тезначения и сброс значений вектора перемещения.

Для данных вектора это в основном эквивалентно

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

Нет необходимости выделять новую память и копировать данныев векторе.

0 голосов
/ 23 декабря 2018

Весь смысл операции перемещения состоит в том, чтобы избежать копирования элементов, поэтому, если бы они были скопированы (нет такой вещи, как «перемещение» памяти), перемещение было бы просто копией.

Векторы обычно реализуются в виде 3 указателей: начало, конец и емкость.Все указывают на динамически размещенный массив.Затем перемещение вектора просто копирует эти три указателя, поэтому массив и элементы просто меняют своего владельца.

Я думаю, что можно с уверенностью предположить, что указатели на элементы остаются действительными.

0 голосов
/ 23 декабря 2018

Будет понятно, если мы напишем семантически равный код без 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));

На самом деле, перемещение вектора сводится к копированию указателя без перераспределения.Данные, на которые указывает указатель, остаются на своем месте, поэтому адреса векторных элементов не меняются.

В этом примере кода после четвертой строки и pre, и post указывают на одни и те же данные с одинаковымиaddress.

std::vector - это оболочка для указателя на массив с некоторыми дополнительными функциями.Таким образом, после выполнения std::vector<B> post(std::move(pre));, post будет содержать указатель с тем же значением, которое было в pre.

...