Sobes.tech
Middle

Wat gebeurt er met de elementen van std::vector tijdens de realloc-operatie?

sobes.tech AI

Antwoord van AI

std::vector gebruikt geen realloc. Wanneer de grootte van de container wordt gewijzigd en geheugen opnieuw moet worden toegewezen, gebeurt het volgende:

  1. Er wordt een nieuw geheugenblok van voldoende grootte toegewezen.
  2. De elementen uit het oude blok worden naar het nieuwe verplaatst.
    • Voor typen die de move-semantiek ondersteunen (T met een correct geïmplementeerde move-constructeur en/of move-toewijzingsoperator), wordt de move gebruikt. Dit is efficiënter, omdat de oude resources (bijvoorbeeld geheugen dat binnen objecten is toegewezen) worden overgedragen aan de nieuwe objecten, en de oude objecten in een geldige maar ongedefinieerde staat blijven of worden schoongemaakt door destructors.
    • Voor typen die geen move-semantiek ondersteunen of als de compiler de move niet kan toepassen, wordt kopiëren gebruikt.
    • Als de elementen triviaal kopieerbaar zijn (T is een POD-type of heeft triviale kopieer- en move-operaties), kunnen memcpy of vergelijkbare low-level functies worden gebruikt om de ruwe gegevens snel te kopiëren.
  3. De destructors worden aangeroepen voor de elementen in het oude geheugen.
  4. Het oude geheugen wordt vrijgegeven.

Het is belangrijk op te merken dat pointers en referenties naar elementen in het oude geheugen ongeldig worden na de herverdeling.

#include <vector>
#include <iostream>
#include <string>

struct MyItem {
    std::string name;
    // Constructor
    MyItem(const std::string& n) : name(n) {
        std::cout << "Constructing " << name << std::endl;
    }
    // Kopieerconstructor
    MyItem(const MyItem& other) : name(other.name) {
        std::cout << "Copying " << name << std::endl;
    }
    // Kopieer toewijzingsoperator
    MyItem& operator=(const MyItem& other) {
        if (this != &other) {
            name = other.name;
            std::cout << "Copy assigning " << name << std::endl;
        }
        return *this;
    }
    // Move constructor
    MyItem(MyItem&& other) noexcept : name(std::move(other.name)) {
        std::cout << "Moving " << name << std::endl;
    }
    // Move toewijzingsoperator
    MyItem& operator=(MyItem&& other) noexcept {
        if (this != &other) {
            name = std::move(other.name);
            std::cout << "Move assigning " << name << std::endl;
        }
        return *this;
    }
    // Destructor
    ~MyItem() {
        std::cout << "Destroying " << name << std::endl;
    }
};

int main() {
    std::vector<MyItem> items;
    items.reserve(2); // Reserveer ruimte voor 2 elementen

    items.emplace_back("item1"); // Zonder realloc
    items.emplace_back("item2"); // Zonder realloc

    std::cout << "Derde item toevoegen, activeert realloc-achtige operatie:" << std::endl;
    items.emplace_back("item3"); // Vereist realloc
    // De uitvoer toont verplaatsing voor item1 en item2, gevolgd door destructie van oude objecten
    // en constructie van het nieuwe item3.
    // Als MyItem geen move-ondersteuning heeft, wordt kopiëren weergegeven.

    return 0;
}