web-dev-qa-db-fra.com

Comment les éléments vectoriels conservent-ils leur adresse d'origine après un vecteur std :: move?

Comme vous pouvez le constater dans la sortie, les objets du vecteur pre ne sont pas seulement "déplacés" vers le vecteur post, ils ont également conservé leur espace d'adressage d'origine en mémoire. Qu'est-ce qui se passe vraiment derrière ce mouvement? Ce comportement est-il attendu? Supposons que j'ai besoin d'un vecteur distinct de pointeurs sur ces objets. Est-il prudent de supposer qu'après ce déplacement, les objets auront toujours leur adresse d'origine?

En fait, j'ai une classe contenant un vecteur comme celui-ci et le vecteur de pointeurs que j'ai mentionnés en tant que membres. J'ai également supprimé les auteurs de copie et défini ceux de déplacement pour la classe.

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

Sortie:

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

Un vecteur n'est en principe rien d'autre qu'un pointeur sur la mémoire allouée au tas, la longueur actuelle et la capacité actuelle du vecteur.

En "déplaçant" un vecteur, vous ne faites que copier ces valeurs et réinitialiser les valeurs du vecteur déplacé.

Pour les données du vecteur, c'est fondamentalement équivalent à

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

Il n'est pas nécessaire d'allouer une nouvelle mémoire et de copier les données dans le vecteur.

11

L’opération de déplacement vise essentiellement à éviter de copier les éléments. Par conséquent, s’ils étaient copiés (il n’existait pas de véritable "déplacement" de la mémoire), le déplacement ne serait qu'une copie.

Les vecteurs sont généralement implémentés sous la forme de 3 pointeurs: début, fin et capacité. Tous pointent vers un tableau alloué dynamiquement. Déplacer le vecteur ne fait que copier ces trois pointeurs. Le tableau et les éléments changent simplement de propriétaire.

Je pense qu'il devrait être prudent de supposer que les pointeurs sur les éléments restent valables.

1
Quimby

Ce sera clair, si nous écrivons un code sémantiquement égal sans 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));

En fait, le déplacement de vecteur se résume à la copie de pointeur sans réallocation. Les données pointées par le pointeur restent à sa place, donc les adresses des éléments vectoriels ne changent pas.

Dans cet exemple de code après la quatrième ligne, pre et post désignent les mêmes données avec la même adresse.

std::vector est un wrapper pour un pointeur sur tableau avec des fonctionnalités supplémentaires. Ainsi, après avoir effectué std::vector<B> post(std::move(pre));, post contiendra un pointeur avec la même valeur que celle qui était dans pre.

0
Sergey