Middle
Que se passe-t-il avec les éléments de std::vector lors de l'opération realloc?
sobes.tech IA
Réponse de l'IA
std::vector n’utilise pas realloc. Lorsqu’on modifie la taille du conteneur nécessitant une redistribution de mémoire, voici ce qui se passe :
- Une nouvelle zone mémoire de taille suffisante est allouée.
- Les éléments de l’ancienne zone sont déplacés vers la nouvelle.
- Pour les types supportant la sémantique de déplacement (
Tavec un constructeur de déplacement et/ou un opérateur d’affectation de déplacement correctement implémentés), le déplacement est utilisé. C’est plus efficace, car les ressources anciennes (par exemple, la mémoire allouée à l’intérieur des objets) sont transférées aux nouveaux objets, et les anciens restent dans un état valide mais indéfini ou sont nettoyés par les destructeurs. - Pour les types ne supportant pas la sémantique de déplacement ou si le compilateur ne peut pas appliquer le déplacement, la copie est utilisée.
- Si les éléments sont trivially copiable (
Test un type POD ou possède des opérations de copie et de déplacement triviales),memcpyou des fonctions similaires de bas niveau peuvent être utilisées pour copier rapidement les données brutes.
- Pour les types supportant la sémantique de déplacement (
- Les destructeurs sont appelés pour les éléments dans l’ancienne zone.
- L’ancienne zone mémoire est libérée.
Il est important de noter que les pointeurs et références aux éléments dans l’ancienne zone deviennent invalides après la redistribution.
#include <vector>
#include <iostream>
#include <string>
struct MyItem {
std::string name;
// Constructeur
MyItem(const std::string& n) : name(n) {
std::cout << "Constructing " << name << std::endl;
}
// Constructeur de copie
MyItem(const MyItem& other) : name(other.name) {
std::cout << "Copying " << name << std::endl;
}
// Opérateur d’affectation par copie
MyItem& operator=(const MyItem& other) {
if (this != &other) {
name = other.name;
std::cout << "Copy assigning " << name << std::endl;
}
return *this;
}
// Constructeur de déplacement
MyItem(MyItem&& other) noexcept : name(std::move(other.name)) {
std::cout << "Moving " << name << std::endl;
}
// Opérateur d’affectation par déplacement
MyItem& operator=(MyItem&& other) noexcept {
if (this != &other) {
name = std::move(other.name);
std::cout << "Move assigning " << name << std::endl;
}
return *this;
}
// Destructeur
~MyItem() {
std::cout << "Destroying " << name << std::endl;
}
};
int main() {
std::vector<MyItem> items;
items.reserve(2); // Réserve pour 2 éléments
items.emplace_back("item1"); // Sans realloc
items.emplace_back("item2"); // Sans realloc
std::cout << "Adding third item, triggering realloc-like operation:" << std::endl;
items.emplace_back("item3"); // Nécessite realloc
// La sortie montrera le déplacement pour item1 et item2, puis la destruction des anciens objets
// et la construction du nouvel item3.
// Si MyItem ne supportait pas le sémantique de déplacement, il y aurait une copie.
return 0;
}