Curs 6
Curs 6
Curs 6
Curs-6
Gavrilut Dragos
STL (Standard Template Library)
Un set divers de template-uri pentru:
Containere (template-uri ale unor clase care pot contine alte clase)
Iteratori (pointeri pentru parcurgerea template-urilor)
Algoritmi (functii care se pot apela pe un container)
Adaptori
Alocatori
Altele
Utilizarea STL-ului se face incluzand hederele specifice template-ului pe care
vrem sa il folosim.
Pentru usurinta se adauga si “using namespace std;”
Obiectele din STL se pot apela fie prin numele direct (“vector<int> x”)
daca folosim “using namespace std;” sau prin namespace
(“std::vector<int> x”) altfel.
Pot exista mai multe implementari pentru obiectele din STL (acestea
depind puternic de compilator ) ceea ce inseamna ca si performanta
acestora este puternic legata de implementarea lor
STL-Containere
void main(void)
{
vector<Type> v;
vector<Type> v(Size);
}
App.cpp
using namespace std;
#include <vector>
void main(void)
{
vector<int> v;
v.push_back(1);v.push_back(2);
int x = v[1];
int y = v.at(0);
}
STL - Vector
App.cpp
using namespace std;
#include <vector>
class Integer
{
int Value;
public:
Integer() : Value(0) {}
Integer(int v) : Value(v) {}
Integer(const Integer &v) : Value(v.Value) {}
void Set(int v) { Value = v; }
int Get() { return Value; }
};
void main(void)
{
vector<Integer> v;
Integer i(5);
v.push_back(i);
i.Set(6);
printf("i=%d,v[0]=%d\n", i.Get(), v[0].Get());
Item[0]
v Item[1]
Item[2]
i Item[0]
STL - Vector
v.push_back(i)
Aloca spatiu pentru
Count+1 elemente
Item[0] uninit
v Item[1] uninit
Item[2] uninit
uninit
i Item[0]
STL - Vector
v.push_back(i)
Aloca spatiu pentru
Count+1 elemente
Item[0] Item[0]
Copie primele Count
v Item[1] Item[1]
elemente din vectorul
Item[2] Item[2] vechi in cel nou
uninit
i Item[0]
Constructor de
copiere
STL - Vector
v.push_back(i)
Aloca spatiu pentru
Count+1 elemente
Item[0] Item[0]
Copie primele Count
v Item[1] Item[1]
elemente din vectorul
Item[2] Item[2] vechi in cel nou
uninit Dealoc elementele
i Item[0] vechi si leg obiectul v
de array-ul nou
STL - Vector
v.push_back(i)
Aloca spatiu pentru
Count+1 elemente
Item[0]
Copie primele Count
v Item[1]
elemente din vectorul
Item[2] vechi in cel nou
Item[3] Dealoc elementele
i Item[0] vechi si leg obiectul v
de array-ul nou
Constructor de Copii itemul nou in
copiere spatiu alocat pentru el
STL - Vector
Test case:
App-1.cpp
#define INTEGER_SIZE 1000
class Integer
{
int Values[INTEGER_SIZE];
public:
Integer() { Set(0); }
Integer(int value) { Set(value ); }
Integer(const Integer &v) { CopyFrom((int*)v.Values); }
Integer& operator= (const Integer& i) { CopyFrom((int*)i.Values); return *this; }
App-3.cpp
void main(void) App-4.cpp
{
Integer *v = new Integer[100000]; void main(void)
Integer i; {
for (int tr = 0; tr < 100000; tr++) Integer **v = new Integer*[MAX];
{ for (int tr = 0; tr <MAX; tr++)
i.Set(tr); {
v[tr].Set(i); v[tr] = new Integer(tr);
} }
} }
STL - Vector
Studiul s-a desfasurat in urmatorul fel:
Fiecare dintre cele 4 applicatii au fost executate de 10 ori si s-au masurat
timpii in milisecunde
S-au masurat doi timpi: timpul de initializare si timpul de setare a datelor in
vector
App-1.cpp
Durata initializare
void main(void)
{ vector
vector<Integer> v;
Integer i;
2000
1800
1600
1400
1200
1000
800
600
400
200
0
App-1 App-2 App-3 App-4
Init 0 120.5 365.6 0
Set 1936 517 476.7 404.6
Init Set
Pentru parcurgerea unui vector se pot folosi iteratori. Iteratorii pot fi vazuti
ca un echivalent al unui pointer pentru un element al containerului
App.cpp
void main(void)
{
vector<int> v;
v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5);
vector<int>::iterator it;
it = v.begin();
while (it < v.end())
{
printf("%d ", (int)(*it));
it++;
}
}
vector<Number>::iterator i = v.begin();
printf("%d\n", i->Value);
printf("%d\n", (i + 2)->Value);
printf("%d %d", v.front().Value, v.back().Value);
}
App.cpp
class Number
{
...
};
void main(void)
{
vector<Number> v;
v.push_back(Number(1)); v.push_back(Number(2)); v.push_back(Number(3));
v.push_back(Number(4)); v.push_back(Number(5));
vector<Number>::iterator it;
for (it = v.begin(); it != v.end(); it++)
printf("%d ", it->Value);
vector<Number>::reverse_iterator rit;
for (rit = v.rbegin(); rit != v.rend(); rit++)
printf("%d ", rit->Value);
}
v.insert(i + 2, Number(10));
Operatorii de comparatie (==, >=, > , <, !==, <=) sunt suprascrisi
Doi vectori sunt egali daca au acelasi numar de elemente si daca operatorul de
egalitate intre elementele de pe aceleasi pozitie returneaza true.
App.cpp
class Number
{
...
};
void main(void)
{
vector<Number> v1;
vector<Number> v2;
for (int tr = 0; tr < 10; tr++)
{
v1.push_back(Number(tr));
v2.push_back(Number(tr));
}
if (v1 == v2)
printf("V1 egal cu V2");
else
printf("V2 este diferit de V2");
}
App.cpp
class Number
{
bool operator==(const Number &n1) { return Value == n1.Value; }
};
void main(void)
{
vector<Number> v1;
vector<Number> v2;
for (int tr = 0; tr < 10; tr++)
{
v1.push_back(Number(tr));
v2.push_back(Number(tr));
}
if (v1 == v2)
printf("V1 egal cu V2");
else
printf("V2 este diferit de V2");
}
STL - Vector
App.cpp
class Number
{
bool operator==(const Number &n1) const { return Value == n1.Value; }
};
void main(void)
{
vector<Number> v1;
vector<Number> v2;
for (int tr = 0; tr < 10; tr++)
{
v1.push_back(Number(tr));
v2.push_back(Number(tr));
}
if (v1 == v2)
printf("V1 egal cu V2");
else
printf("V2 este diferit de V2");
}
STL - Vector
App.cpp
Function compare(Vector v1,Vector v2)
Size = MINIM(v1.Size,v2.Size)
for (i=0;i<Size;i++)
if (v1[i]<v2[i])
return "v1 mai mic ca v2";
end if
end for
if (v1.Size<v2.Size)
return "v1 mai mic ca v2";
end if
return "v1 NU este mai mic ca v2";
End Function
STL - Vector
v2 = v1;
Metode din template-ul vector care se pot folosi pentru a obtine informatii
despre statusul unui obiect:
size() numarul de elemente din vector
capacity() spatial prealocat pentru un vector
max_size() numarul maxim de elemente care pot exista in acel vector
empty() “true” daca vectorul nu are nici un element
data() pointer catre elementele de tipul “Type” folosit in template.
App.cpp
class Number { ... };
void main(void)
{
vector<Number> v;
v.push_back(Number(0)); v.push_back(Number(1));
printf("%d ", v.max_size());
printf("%d ", v.size());
printf("%d ", v.capacity());
Number *n = v.data();
printf("[%d %d]", n[0].Value, n[1].Value);
}
STL – Deque
Object 5
Object 2
Vector Deque
STL – Deque
Daca reluam experimentul precedent – doar ca de data asta folosim si “deque”
App-1.cpp App-2.cpp
void main(void) void main(void)
{ {
vector<Integer> v; vector<Integer> v;
Integer i; Integer i;
for (int tr = 0; tr < 100000; tr++) v.reserve(100000);
{ for (int tr = 0; tr < 100000; tr++)
i.Set(tr); {
v.push_back(i); i.Set(tr);
} v.push_back(i);
} }
}
App-5.cpp
void main(void)
{
deque<Integer> v;
Integer i;
for (int tr = 0; tr < 100000; tr++)
{
i.Set(tr);
v.push_back(i);
}
}
STL – Deque
Rezultate:
2000
1800
1600
1400
1200
1000
800
600
400
200
0
App-1 App-2 App-5
Init 0 120.5 0
Set 1936 517 651.4
Init Set
App.cpp
class Number
{
...
};
void main(void)
{
array<Number,5> v;
v.fill(Number(2));
for (int tr = 0; tr < v.size(); tr++)
printf("%d ", v[tr].Value);
App.cpp App.cpp
reference at(size_type _Pos) reference operator[](size_type _Pos)
{ {
if (_Size <= _Pos) #if _ITERATOR_DEBUG_LEVEL == 2
_Xran(); if (_Size <= _Pos)
return (_Elems[_Pos]); _DEBUG_ERROR("array subscript out of range");
} #elif _ITERATOR_DEBUG_LEVEL == 1
_SCL_SECURE_VALIDATE_RANGE(_Pos < _Size);
#endif
_Analysis_assume_(_Pos < _Size);
return (_Elems[_Pos]);
}
cu
#define _Analysis_assume_(expr) // pentru release
list<Number>::iterator it;
for (it = v.begin(); it < v.end(); it++)
printf("%d ", it->Value);
it = v.begin()+3;
v.insert(it, Number(20));
for (it = v.begin(); it != v.end(); it++)
printf("%d ", it->Value);
it = ++v.begin();
v.erase(it);
for (it = v.begin(); it != v.end(); it++)
printf("%d ", it->Value);
}
Codul nu compileaza pentru ca iteratorul din lista nu suporta comparatie < sau >
STL - List
list<Number>::iterator it;
for (it = v.begin(); it != v.end(); it++)
printf("%d ", it->Value);
it = v.begin()+3;
v.insert(it, Number(20));
for (it = v.begin(); it != v.end(); it++)
printf("%d ", it->Value);
it = ++v.begin();
v.erase(it);
for (it = v.begin(); it != v.end(); it++)
printf("%d ", it->Value);
}
list<Number>::iterator it;
for (it = v.begin(); it != v.end(); it++)
printf("%d ", it->Value);
it = v.begin();it++;it++;it++;
v.insert(it, Number(20));
for (it = v.begin(); it != v.end(); it++)
printf("%d ", it->Value);
it = ++v.begin();
v.erase(it);
for (it = v.begin(); it != v.end(); it++)
printf("%d ", it->Value);
}
forward_list<Number>::iterator it;
for (it = v.begin(); it != v.end(); it++)
printf("%d ", it->Value);
it = v.begin();
it++; it++;
v.insert_after(it, Number(20));
for (it = v.begin(); it != v.end(); it++)
printf("%d ", it->Value);
it = ++v.begin();
v.erase_after(it);
for (it = v.begin(); it != v.end(); it++)
printf("%d ", it->Value);
}
Adaptorul care este o expresie pentru o stiva (LIFO – Last In First Out)
Pentru utilzare “#include <stack>”
Containerul implicit este “deque” (in exemplu de mai jos “s” foloseste deque
iar “s2” vector)
App.cpp
void main(void)
{
stack<int> s;
s.push(10); s.push(20); s.push(30);
Adaptorul care este o expresie pentru o coada (FIFO – First In First Out)
Pentru utilzare “#include <queue>”
Containerul implicit este “deque” (in exemplu de mai jos “s” foloseste deque
iar “s2” list)
App.cpp
void main(void)
{
queue<int> s;
s.push(10); s.push(20); s.push(30);
Adaptorul care este o expresie pentru o coada in care fie fiecare element are o
prioritate asociata lui. Elementele sunt ordonate dupa prioritate in coada.
Pentru utilzare “#include <queue>”
Containerul implicit este “vector”
App.cpp
void main(void)
{
priority_queue<int> s;
s.push(10); s.push(5); s.push(20); s.push(15);
while (s.empty() == false)
{
printf("%d ", s.top());
s.pop();
}
}
App.cpp
class CompareModule
{
int modValue;
public:
CompareModule(int v) : modValue(v) {}
bool operator() (const int& v1, const int& v2) const
{
return (v1 % modValue) < (v2 % modValue);
}
};
void main(void)
{
priority_queue<int, vector<int>, CompareModule> s(CompareModule(3));
s.push(10); s.push(5); s.push(20); s.push(15);
while (s.empty() == false)
{
printf("%d ", s.top());
s.pop();
}
}