std::vector::push_back în C++

std::vector C++98

Adaugă un element la sfârșitul vectorului; vectorul crește cu o poziție.

Sintaxă
void push_back(const T& valoare);
void push_back(T&& valoare);   // C++11

Ce face std::vector::push_back

push_back pune o copie a valorii (sau valoarea mutată, dacă este temporară) după ultimul element. Este modul obișnuit de a construi un vector pas cu pas, de exemplu când citești date.

Vectorul are o capacitate rezervată (capacity()). Cât timp mai este loc, push_back doar scrie elementul. Când capacitatea este plină, vectorul alocă o zonă mai mare, mută toate elementele acolo și eliberează zona veche. De aceea, în medie, adăugarea la final este rapidă, dar uneori costă mai mult.

Atenție la invalidarea iteratorilor: dacă push_back realocă memoria, toate iteratorii, pointerii și referințele la elementele vectorului devin invalide. Dacă nu realocă, devine invalid doar end().

Parametri

Parametru Descriere
valoare Elementul de adăugat. Trebuie să aibă tipul elementelor vectorului (sau să poată fi convertit la el).

Ce returnează

Nimic (void). Noul element este v.back().

Exemple

Exemplul 1: Construirea unei liste de cumpărături

#include <print>
#include <string>
#include <vector>

int main() {
    std::vector<std::string> cos;
    cos.push_back("mere");
    cos.push_back("brânză");
    std::string produs = "cafea";
    cos.push_back(produs);           // se copiază

    std::println("{} produse: {}", cos.size(), cos);
    std::println("Ultimul adăugat: {}", cos.back());
}

Rezultat

3 produse: ["mere", "brânză", "cafea"]
Ultimul adăugat: cafea

Exemplul 2: Când se realocă memoria

Afișăm capacitatea după fiecare adăugare. Creșterea exactă (aici dublare) depinde de implementarea bibliotecii; rezultatul este cel de pe libc++ (clang).

#include <print>
#include <vector>

int main() {
    std::vector<int> v;
    for (int i = 1; i <= 9; ++i) {
        std::size_t inainte = v.capacity();
        v.push_back(i);
        if (v.capacity() != inainte) {
            std::println("size {}: capacitatea a crescut de la {} la {} (realocare)", v.size(), inainte, v.capacity());
        }
    }
}

Rezultat

size 1: capacitatea a crescut de la 0 la 1 (realocare)
size 2: capacitatea a crescut de la 1 la 2 (realocare)
size 3: capacitatea a crescut de la 2 la 4 (realocare)
size 5: capacitatea a crescut de la 4 la 8 (realocare)
size 9: capacitatea a crescut de la 8 la 16 (realocare)

Exemplul 3: Iterator păstrat corect după adăugare

Un iterator vechi nu mai este sigur după push_back. Soluția simplă: păstrează poziția (indicele), nu iteratorul, și calculează iteratorul din nou când ai nevoie.

#include <print>
#include <vector>

int main() {
    std::vector<int> v{10, 20, 30};
    std::size_t poz = 1;              // vrem să urmărim elementul 20

    for (int i = 0; i < 100; ++i) {
        v.push_back(i);               // poate realoca de mai multe ori
    }
    auto it = v.begin() + static_cast<std::ptrdiff_t>(poz);   // iterator nou, valid
    std::println("Elementul urmărit: {}", *it);
    std::println("Vectorul are acum {} elemente", v.size());
}

Rezultat

Elementul urmărit: 20
Vectorul are acum 103 elemente

Greșeli frecvente

  • Păstrezi un iterator, pointer sau referință la un element (int& primul = v[0];) și apoi faci push_back. Dacă vectorul a realocat, primul arată spre memorie eliberată: comportament nedefinit.
  • Adaugi în vector în timp ce îl parcurgi cu for (int x : v). Bucla folosește iteratori, care pot fi invalidați. Parcurge cu indice și salvează dimensiunea înainte, sau adaugă într-un vector separat.
  • Faci mii de push_back când știi dinainte câte elemente vor fi. Apelează întâi reserve(n) ca să eviți realocările repetate.

Comenzi înrudite

  • std::vector::emplace_back: Construiește un element nou direct la sfârșitul vectorului, din argumentele constructorului.
  • std::vector::pop_back: Șterge ultimul element al vectorului; dimensiunea scade cu 1.
  • std::vector::reserve: reserve() rezervă memorie pentru n elemente, capacity() spune cât loc este rezervat, iar shrink_to_fit() cere eliberarea locului nefolosit.
  • std::vector::insert: Inserează unul sau mai multe elemente înaintea unei poziții din vector; emplace construiește elementul pe loc.
  • std::back_inserter: Iteratori de inserare: fiecare scriere prin back_inserter face push_back, iar prin inserter face insert la o poziție.