Sobes.tech
Middle

Co se děje s prvky std::vector při operaci realloc?

sobes.tech AI

Odpověď od AI

std::vector nepoužívá realloc. Při změně velikosti kontejneru, která vyžaduje přerozdělení paměti, se děje následující:

  1. Vyhradí se nová oblast paměti dostatečné velikosti.
  2. Elementy z staré oblasti se přesunou do nové.
    • U typů podporujících přesunovou semantiku (T s korektní implementací konstruktoru přesunu a/nebo operátoru přiřazení přesunu) se použije přesun. To je efektivnější, protože staré zdroje (například paměť alokovaná uvnitř objektů) jsou předány novým objektům a staré objekty zůstanou v platném, ale neurčitelném stavu nebo jsou zničeny destruktory.
    • U typů, které nepodporují přesun nebo pokud překladač nemůže přesun použít, se použije kopírování.
    • Pokud jsou prvky triviálně kopírovatelné (T je POD typ nebo má triviální operace kopírování a přesunu), může být použita funkce memcpy nebo podobná nízkoúrovňová funkce pro rychlé kopírování surových dat.
  3. Destruktory jsou volány pro prvky ve staré oblasti paměti.
  4. Staré oblasti paměti jsou uvolněny.

Je důležité poznamenat, že ukazatele a odkazy na prvky ve staré oblasti paměti se po přerozdělení stanou neplatnými.

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

struct MyItem {
    std::string name;
    // Konstruktor
    MyItem(const std::string& n) : name(n) {
        std::cout << "Constructing " << name << std::endl;
    }
    // Konstruktor kopírování
    MyItem(const MyItem& other) : name(other.name) {
        std::cout << "Copying " << name << std::endl;
    }
    // Operátor přiřazení kopírováním
    MyItem& operator=(const MyItem& other) {
        if (this != &other) {
            name = other.name;
            std::cout << "Copy assigning " << name << std::endl;
        }
        return *this;
    }
    // Konstruktor přesunu
    MyItem(MyItem&& other) noexcept : name(std::move(other.name)) {
        std::cout << "Moving " << name << std::endl;
    }
    // Operátor přiřazení přesunem
    MyItem& operator=(MyItem&& other) noexcept {
        if (this != &other) {
            name = std::move(other.name);
            std::cout << "Move assigning " << name << std::endl;
        }
        return *this;
    }
    // Destruktor
    ~MyItem() {
        std::cout << "Destroying " << name << std::endl;
    }
};

int main() {
    std::vector<MyItem> items;
    items.reserve(2); // Rezervace paměti pro 2 prvky

    items.emplace_back("item1"); // Bez reallokace
    items.emplace_back("item2"); // Bez reallokace

    std::cout << "Adding third item, triggering realloc-like operation:" << std::endl;
    items.emplace_back("item3"); // Vyžaduje reallokaci
    // Výstup ukáže přesun prvků item1 a item2, následně destrukci starých objektů
    // a konstrukci nového item3.
    // Pokud by MyItem nepodporoval přesun, byla by výstup o kopírování.

    return 0;
}