Standard Template Library (STL)

Bibliotecă de clase, parte din standard library.

Oferă structuri de date și algoritmi fundamentali. Oferă componente generice, parametrizabile (aproape toate clasele din STL sunt parametrizabile -> templates).

STL conține clase pentru:

Container

Tipuri de container:

Vector

template <class T, class Allocator = allocator<T>> class vector

T = tipul de date. Allocator = tipul de alocator utilizat (de obicei cel standard).

Constructori

Utilizarea constructorilor pentru vector.

vector<int> iv; // vector de int cu 0 elemente 

vector<int> iv(10); // vector de int cu 10 elemente, se initializeaza cu 0

vector<int> iv(10, 7); // vector de int cu 10 elemente, fiecare egal cu 7 

vector<int> iv2(iv); // vector de int reprezentand copia lui iv 

////
list<int> L = {1, 2, 3, 4};
vector<int> v_din_list(L.begin(), L.end()); 
resize

Pentru accesarea/inserarea valorilor cu indice:
Pentru un vector declarat cu dimensiune fixă, trebuie schimbată dimensiunea cu resize(). Nu cauzează eroare, dar valorile nu sunt luate în considerare pentru un indice >= v.size().

Dacă se lucrează cu push_back() size-ul e este schimbat automat.

template <typename T>
void print(const vector<T>& v) {
    for(int i = 0; i < v.size(); i++)
        cout << v[i] << " ";
    cout << endl;
}

int main() {
    vector<int> v(3);
    print(v); // 0 0 0
    v[0] = 3;
    v[1] = 4;
    v[2] = 5;
    v[3] = 7;
    print(v); // 3 4 5 (7 nu e stocat in vector)
    v.resize(5);
    v[3] = 7; 
    print(v); // 3 4 5 7 0
    return 0;
}

Se pot insera/șterge elemente și cu iteratori.

vector<int> v(10);
vector<int>::iterator it;
int i = 0;
for(it = v.begin(); it != v.end(); it++, i++)
	*it = i;
print(v); // 0 1 ... 9

Insert

it = v.begin() + 2;
v.insert(it, 3, 999); // insereaza 3 de 999 inainte de al treilea element din v

Erase

Șterge elementul de la o poziție marcată printr-un iterator, sau între doi iteratori.

Listă

Implementată ca listă dublu înlănțuită.

Constructori

list<int> iv;

list<int> iv(10);

list<int> iv(10, 7);

list<int> iv2(iv); // copie 

list<int> iv3(iv.begin(), iv.end());
Specific list

Pot fi merge-uite list<T>::merge(list<T>& other);
Nu pot fi accesate prin indice.

Apelare constructori

class Test {
    int i;
public:
    Test(int x = 0) : i(x) { cout << "C" << x << " "; }
    Test(const Test& x) { i = x.i, cout << "CC" << i << " "; }
    ~Test() { cout << "D" << i << " ";}
};

int main() {
    list<Test> v(3);
    cout << endl;
    v.push_back(10);
    cout << endl;
    v.push_back(11);
    cout << endl;
    v.push_back(12);
    cout << endl;
    Test ob(13);
    v.push_back(ob);
    cout << endl;
}

Va afișa

C0 C0 C0 // se construiesc atunci cand se initializeaza lista
C10 CC10 D10 // se construieste un obiect temporar, este copiat in lista, se sterge obiectul temporar
C11 CC11 D11 
C12 CC12 D12 
C13 CC13 
D13 D0 D0 D0 D10 D11 D12 D13 // de-abia la final sunt șterse elementele din lista

Deque

Adaptor de container

În capsulează un container de tip secvență și folosesc acest obiect pentru a oferi funcționalități specifice container-ului.

Stack

template <class T, class Container = deque<T>> class stack;
stack<int, vector<int>> s;  // primul parametru, tipul elementelor 
							// al doilea parametru, modul de stocare

Cu clasa Test definită anterior putem arăta importanța celui de-al doilea parametru:

int main() {
	stack<Test> s;
	cout << endl;
	s.push(1);
	cout << endl;
	s.push(2);
	cout << endl;
	s.push(3);
	cout << endl;
}

Afișează

C1 CC1 D1 // construcția unui obiect temporar, copiere și distrugere
C2 CC2 D2 
C3 CC3 D3 
D1 D2 D3 // distrugerea listei 

În acest caz, este folosit implicit deque<Test>, care, pentru că lucrează prin blocuri de memorie, nu trebuie decât să găsească memorie pentru a stoca obiectele noi (obiectele anterioare nu trebuie mutate).

Dacă folosim vector

int main() {
	stack<Test, vector<Test>> s;
	cout << endl;
	s.push(1);
	cout << endl;
	s.push(2);
	cout << endl;
	s.push(3);
	cout << endl;
}

Va afișa

C1 CC1 D1 
C2 CC2 CC1 D1 D2 
C3 CC3 CC1 CC2 D1 D2 D3 
D1 D2 D3 

vector ține obiectele într-un bloc continuu de memorie. Atunci când este depășit buffer-ul alocat pentru vector, trebuie căutat o nouă zonă de memorie și toate elementele anterioare sunt copiate în această nouă zonă. Acest lucru se întâmplă în incremente de puteri ale lui 2.

Explicarea exemplului anterior

Dacă am continua, se poate observa doar copierea în pași de 2n.

int main() {
    stack<Test, vector<Test>> a;
    cout << endl;
    for(int i = 0; i < 16; i ++) {
        a.push(i);
        cout << endl;
    }
}

Va afișa

C0 CC0 D0 
C1 CC1 CC0 D0 D1 
C2 CC2 CC0 CC1 D0 D1 D2 
C3 CC3 D3 
C4 CC4 CC0 CC1 CC2 CC3 D0 D1 D2 D3 D4 
C5 CC5 D5 
C6 CC6 D6 
C7 CC7 D7 
C8 CC8 CC0 CC1 CC2 CC3 CC4 CC5 CC6 CC7 D0 D1 D2 D3 D4 D5 D6 D7 D8 
C9 CC9 D9 
C10 CC10 D10 
C11 CC11 D11 
C12 CC12 D12 
C13 CC13 D13 
C14 CC14 D14 
C15 CC15 D15 
D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12 D13 D14 D15 

Containere asociative

Set

Map

template <class Key, class T, class Comp = less<Key>, class Allocator =  allocator <pair<const Key,T> > class map
Inserarea se face ordonat după chei

Tipuri de constructori

map<char, int> m; // map cu zero elemente 

map<char, int> m2(m); // copiere 

map<char, int> m3(m.begin(), m.end()); // range constructor

Exemplu utilizare iterator:

int main() {
    map<int, int> m;
    m.insert(pair<int, int>(1,2));
    m.insert(pair<int, int>(3, 4));
    m.insert(pair<int, int>(5, 6));
    m.insert(pair<int, int>(7, 8));
    m.insert(pair<int, int>(9, 10));
    map<int, int>::iterator p;
    for(p = m.begin(); p != m.end(); p++)
        cout << p->first << " " << p->second << endl;
}

Bitset

Iterator

Warning

Adaptoarele de containere nu oferă iteratori.

De mai multe tipuri

vector<int>::reverse_iterator r;
for (r = v.rbegin(); r != v.rend(); r++)
	cout << *r << " ";

Algorithm

Colecție de funcții template care pot fi folosite cu iteratori.

Exemple:

Lambda expressions

Sintaxa:

[capture](parameters) mutable exception -> return type {body}
int a = 1, b = 2, c = 3;
auto k = [a, &b](int x) {
	return a + b + x;
} // a e copiat, b se transmite prin referinta, c nu e accesibil

auto k1 = [=](int x) {
	return a * x;
} // copiaza a 

auto k2 = [&](int x) { 
	return b = x*a; 
} // a, b se transmite prin referinta 
capture

Singurele lucruri admise în capture sunt nume de variabile, &, = și this.

Warning

Variabilele utilizate trebuie declarate în funcție sau în capture.

int c = 2;
auto k = [](int x) {
	return c * x; // eroare, c nu poate fi accesat
}
Alte erori

  • Dacă a fost declarat deja &, nu mai pot fi utilizate alte variabile cu & în față.
  • Dacă conține = by default, nu mai pot fi utilizate alte argumente tot prin valoare.
int i = 2;
[&, i]{}; // ok 
[&, &i]{}; // eroare
[=, this]{}; // eroare
[=, *this] {}; // ok
[i, i]{}; // eroare, se repeta i

Deducerea tipului în mod automat

Auto

Tipul poate fi dedus din inițializarea variabilei respective. În cazul funcțiilor, dacă tipul inițializat este auto, este evaluat din expresia returnată la runtime.

Eroare

Variabilele auto trebuie inițializate, altfel eroare.

Decltype

Returnează tipul unei expresii fără a o evalua.

decltype(expression) name;