Sobes.tech
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 :

  1. Une nouvelle zone mémoire de taille suffisante est allouée.
  2. Les éléments de l’ancienne zone sont déplacés vers la nouvelle.
    • Pour les types supportant la sémantique de déplacement (T avec 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 (T est un type POD ou possède des opérations de copie et de déplacement triviales), memcpy ou des fonctions similaires de bas niveau peuvent être utilisées pour copier rapidement les données brutes.
  3. Les destructeurs sont appelés pour les éléments dans l’ancienne zone.
  4. 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;
}