Introdução à STL (Standard  Template Library) Felipe Sampaio, Robson Dornelles, Gerson Geraldo H. Cavalheiro
Templates É uma ferramenta da linguagem C++ para a geração de código genérico template<class tipo> tipo soma(tipo a, tipo b) { return a + b; } printf(“%d”, soma<int> (1,2)); printf(“%f”, soma<float> (1.4,2.6)); O código acima funciona para qualquer tipo que tenha o operador “+” sobrecarregado
Templates typedef struct minha_string { char *str; minha_string(char* s) { str = (char*) malloc(sizeof(strlen(s))); strcpy(str,s); } minha_string operator+(minha_string b) { minha_string n(strcat(str,b.str)); return n; } }MINHA_STR; int main() { MINHA_STR a(&quot;abc&quot;); MINHA_STR b(&quot;def&quot;); printf(&quot;%s\n&quot;, soma<MINHA_STR> (a,b).str); return 0; }
Afinal, o que é? Parte do ISO Standard C++ Library STL = Standard Template Library A STL implementa várias estruturas de dados, no formato de classes, utilizando templates Assim, é possível guardar qualquer tipo nessas estruturas Documentação oficial: www.sgi.com/tech/stl
Por que usar? Redução do tempo de desenvolvimento. Código pronto e depurado. Legibilidade de código Além de utilizar código padrão, o programa desenvolvido fica mais enxuto. Robustez As estruturas de dados de STL crescem automaticamente. Código portável Usa um padrão. Facilita a manutenção As estruturas de dados são, até certo ponto, intercambiáveis É fácil!
Componentes básicos Trata-se de uma biblioteca que define: Containers Estruturas de dados Iterators Iteradores para percorrer as estruturas de dados Algoritmos Oferecem serviços (funcões) para as estruturas de dados (busca, ordenação...)
Containers “top of mind” map  Possui dois campos, uma chave e um valor, ambos campos podem ser de qualquer tipo e de qualquer valor O conteúdo é mantido ordenado vector  Semelhante a um vetor em C/C++, mas cresce automáticamente. list  Semelhante ao vetor, mas implementada como uma lista encadeada
Uso do vector Métodos unsigned int size(); Retorna o número de elementos de um vetor push_back(type element); Insere, no fim, um novo elemento bool empty(); Retorna true se o vetor esta vazio void clear(); Remove todos os elementos do vetor type at(int n); Retorna o elemento que está na posição indicada, fazendo o teste de limites
Uso do vector Operadores = Substitui o conteúdo do vetor destino com o conteúdo do vetor informado == Compara o conteúdo (elemento a elemento) do vetor [] Acesso à uma posição do vetor – sem teste de limites!
Uso do vector Alocação prévia da área de dados vector<int> v(100); v[80] = 1;  // Funciona! v[200]= 1;  // Ups... Crescimento automático vector<int> v2; int i; while( std::cin >> I ) v.push_back(i);
Uso do vector #include <iostream> #include <vector> using namespace std; int main() { int i; vector <int> example;  example.push_back(3);  example.push_back(10);  example.push_back(33); for( i = 0 ; i < example.size() ; i++)  cout << example[i] << &quot; &quot;; ... }
Uso do vector #include <iostream> #include <vector> using namespace std; int main() { vector <int> example; vector <int> another_vector; another_vector.push_back(10); example.push_back(10); if( example == another_vector ) example.push_back(20);  for( i = 0 ; i < example.size() ; i++)  cout << example[i] << &quot; &quot;; return 0; }
Uso de list Métodos unsigned int size(); Retorna o número de elementos de um vetor push_back/front(type element); Insere, no fim/início, um novo elemento pop_back/front(); Retira o último/primeiro elemento back/front(); Retorna o último/primeiro elemento iterator insert(iterator pos, const T& x); Insere um elemento após a posição indicada empty, clear, swap, resize, split, merge, ...
Uso de list Operadores = Substitui o conteúdo do vetor destino com o conteúdo do vetor informado == Compara o conteúdo (elemento a elemento) do vetor < Comparação lexicográfica
Uso de list int i; list<int> lst;  for( i = 1 ; i <= 5 ; ++i ) lst.push_back(i); for( i = 10 ; i > 5 ; ++i )  lst.push_front(i); ...
Uso de map Estrutura de dados que faz uma associação entre valores de dois tipos de dados distintos Chave Dado Não pode haver dois dados com a mesma chave!
Uso de map Métodos size, empty, clear, swap, ... iterator find(const key_type& k) Retorna a posição onde o elemento identificado pela chave se encontra size_type count(const key_type& k) Retorna o número de elementos que possui a chave indicada (que deve ser, no map, 1 ou 0)
Uso de map Operadores [] Onde é informada a chave = Operação de atribuição == Compara dois maps < Teste lexicográfico
Uso de map long aux; map<long,int> raiz; raiz[4] = 2; raiz[1000000] = 1000; std::cin >> aux; if( root.count(aux) != 0 ) std::cout << root[l] else std::cout << &quot;Nao tem raiz perfeita!&quot;;
Uso de map #include <map> double bancaSaoJoao( const caipira& caipa ) { map<char*,float,ltstr> preco; char  item[20]; double conta = 0.0; price[&quot;carapinha&quot;] = 0.75; preco[&quot;quentao&quot;]  = 1.5; preco[&quot;pinhao&quot;]  = 1.25; preco[&quot;pipoca&quot;]  = 0.75; while( std::cin >> item ) { item = caipa.whatYouWantBaby(); conta += price[item]; } return conta; }
Uso de map #include <map> struct ltstr { bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) < 0; } }; double bancaSaoJoao( const caipira& caipa ) { map<char*,float,ltstr> preco; char  item[20]; double conta = 0.0; preco[&quot;carapinha&quot;] = 0.75; ...
Uso de map int main() { map<const char*, int, ltstr> months; months[&quot;january&quot;] = 31;  months[&quot;february&quot;] = 28; months[&quot;march&quot;] = 31;  months[&quot;april&quot;] = 30; months[&quot;may&quot;] = 31;  months[&quot;june&quot;] = 30; months[&quot;july&quot;] = 31;  months[&quot;august&quot;] = 31; months[&quot;september&quot;] = 30;  months[&quot;october&quot;] = 31; months[&quot;november&quot;] = 30;  months[&quot;december&quot;] = 31; cout << &quot;june -> &quot; << months[&quot;june&quot;] << endl; map<const char*, int, ltstr>::iterator cur  = months.find(&quot;june&quot;); map<const char*, int, ltstr>::iterator prev = cur; map<const char*, int, ltstr>::iterator next = cur;  ++next; --prev; cout << &quot;Previous (in alphabetical order) is &quot; << (*prev).first << endl; cout << &quot;Next (in alphabetical order) is &quot; << (*next).first << endl; }
Iterators Declaração Identificação do container. list<int> lst; list<int>::iterator  li; Acesso ao início da lista: li = lst.begin(); Acesso ao fim da lista: li = lst.end(); Acesso ao elemento int aux; aux = *li;
Iterators Permite “passear” nos containers list<int> lst; list<int>::iterator li; for( li = lst.begin() ; lst != lst.end() ; lst++ ) std::cout << *it << std::endl; // também pode: li = lst.begin(); *li = 313;
Algoritmos Permitem percorrer containters executando operações pré-definidas Existem vários, diversos e variados. Exemplo list<int>  lst; vector<int> vet; copy(lst.begin(), lst.end(), vet.begin()); copy(lst.begin(), lst.end(), ostream_iterator<int>(cout, &quot;,&quot;)); sort(lst.begin(), lst.last() );
Criando classes para serem incluidas em containers Obrigatório: Definir o operador de cópia: operator=(const T&) Implementar o construtor default: T() Implementar o construtor de cópia: T(const T&) Caso o container desejado seja ordenado, ex:  map<> Deve ser definido o operador “menor-que”: operator<() Alguns tipos primitivos possuem: int, char, string Outros não: char *
Exemplo de tipo definido pelo usuário Agenda de nomes struct Nome { char* prenome; char* sobrenome; bool operator<(const Nome& n) { return strcmp(prenome, n.prenome) < 0; } } map<Nome,int> agenda;
Cuidados Acesso à posição inválida de  vector<> . vector<int> v; v[100] = 1;  // Ups! Solução: Utilizar a interface prevista: push_back() reserve() capacity() Pré-alocar no construtor.
Cuidados Cuidar para não criar elementos no  map<>  de forma inadvertida if( toto[&quot;bob&quot;] == 1 ) ... Se  bob  não existia em  toto , agora existe! Evite utilizando  count()  para verificar se a entrada existe. if( toto.count(&quot;bob&quot;) ) ...
Cuidados Utilizar a interface de serviços observando o desempenho: Exemplo: empty()  em  list<>  . Muito lento if( lst.count() == 0 ) { ... } Bem mais rápido if( lst.empty() ) {...} Como saber? Estudando a STL...
Cuidados Utilizar um iterador invalidado list<int> lst; list<int>::iterator li; li = lst.begin(); lst.erase(li); ++li;  // Ups! Utilizar o retorno do erase para avançar li = lst.erase(li);  // Ok!
Erro de compilação comum! Erro de compilação comum!   vector<vector<int>> vet; Falta de espaço! O analisador léxico entende como right-shift.
Muitos outros containers set ,  multiset ,  multimap queue ,  priority_queue   stack  ,  deque   slist ,  bitset ,  valarray

C++ Standard Template Library

  • 1.
    Introdução à STL(Standard Template Library) Felipe Sampaio, Robson Dornelles, Gerson Geraldo H. Cavalheiro
  • 2.
    Templates É umaferramenta da linguagem C++ para a geração de código genérico template<class tipo> tipo soma(tipo a, tipo b) { return a + b; } printf(“%d”, soma<int> (1,2)); printf(“%f”, soma<float> (1.4,2.6)); O código acima funciona para qualquer tipo que tenha o operador “+” sobrecarregado
  • 3.
    Templates typedef structminha_string { char *str; minha_string(char* s) { str = (char*) malloc(sizeof(strlen(s))); strcpy(str,s); } minha_string operator+(minha_string b) { minha_string n(strcat(str,b.str)); return n; } }MINHA_STR; int main() { MINHA_STR a(&quot;abc&quot;); MINHA_STR b(&quot;def&quot;); printf(&quot;%s\n&quot;, soma<MINHA_STR> (a,b).str); return 0; }
  • 4.
    Afinal, o queé? Parte do ISO Standard C++ Library STL = Standard Template Library A STL implementa várias estruturas de dados, no formato de classes, utilizando templates Assim, é possível guardar qualquer tipo nessas estruturas Documentação oficial: www.sgi.com/tech/stl
  • 5.
    Por que usar?Redução do tempo de desenvolvimento. Código pronto e depurado. Legibilidade de código Além de utilizar código padrão, o programa desenvolvido fica mais enxuto. Robustez As estruturas de dados de STL crescem automaticamente. Código portável Usa um padrão. Facilita a manutenção As estruturas de dados são, até certo ponto, intercambiáveis É fácil!
  • 6.
    Componentes básicos Trata-sede uma biblioteca que define: Containers Estruturas de dados Iterators Iteradores para percorrer as estruturas de dados Algoritmos Oferecem serviços (funcões) para as estruturas de dados (busca, ordenação...)
  • 7.
    Containers “top ofmind” map Possui dois campos, uma chave e um valor, ambos campos podem ser de qualquer tipo e de qualquer valor O conteúdo é mantido ordenado vector Semelhante a um vetor em C/C++, mas cresce automáticamente. list Semelhante ao vetor, mas implementada como uma lista encadeada
  • 8.
    Uso do vectorMétodos unsigned int size(); Retorna o número de elementos de um vetor push_back(type element); Insere, no fim, um novo elemento bool empty(); Retorna true se o vetor esta vazio void clear(); Remove todos os elementos do vetor type at(int n); Retorna o elemento que está na posição indicada, fazendo o teste de limites
  • 9.
    Uso do vectorOperadores = Substitui o conteúdo do vetor destino com o conteúdo do vetor informado == Compara o conteúdo (elemento a elemento) do vetor [] Acesso à uma posição do vetor – sem teste de limites!
  • 10.
    Uso do vectorAlocação prévia da área de dados vector<int> v(100); v[80] = 1; // Funciona! v[200]= 1; // Ups... Crescimento automático vector<int> v2; int i; while( std::cin >> I ) v.push_back(i);
  • 11.
    Uso do vector#include <iostream> #include <vector> using namespace std; int main() { int i; vector <int> example; example.push_back(3); example.push_back(10); example.push_back(33); for( i = 0 ; i < example.size() ; i++) cout << example[i] << &quot; &quot;; ... }
  • 12.
    Uso do vector#include <iostream> #include <vector> using namespace std; int main() { vector <int> example; vector <int> another_vector; another_vector.push_back(10); example.push_back(10); if( example == another_vector ) example.push_back(20); for( i = 0 ; i < example.size() ; i++) cout << example[i] << &quot; &quot;; return 0; }
  • 13.
    Uso de listMétodos unsigned int size(); Retorna o número de elementos de um vetor push_back/front(type element); Insere, no fim/início, um novo elemento pop_back/front(); Retira o último/primeiro elemento back/front(); Retorna o último/primeiro elemento iterator insert(iterator pos, const T& x); Insere um elemento após a posição indicada empty, clear, swap, resize, split, merge, ...
  • 14.
    Uso de listOperadores = Substitui o conteúdo do vetor destino com o conteúdo do vetor informado == Compara o conteúdo (elemento a elemento) do vetor < Comparação lexicográfica
  • 15.
    Uso de listint i; list<int> lst; for( i = 1 ; i <= 5 ; ++i ) lst.push_back(i); for( i = 10 ; i > 5 ; ++i ) lst.push_front(i); ...
  • 16.
    Uso de mapEstrutura de dados que faz uma associação entre valores de dois tipos de dados distintos Chave Dado Não pode haver dois dados com a mesma chave!
  • 17.
    Uso de mapMétodos size, empty, clear, swap, ... iterator find(const key_type& k) Retorna a posição onde o elemento identificado pela chave se encontra size_type count(const key_type& k) Retorna o número de elementos que possui a chave indicada (que deve ser, no map, 1 ou 0)
  • 18.
    Uso de mapOperadores [] Onde é informada a chave = Operação de atribuição == Compara dois maps < Teste lexicográfico
  • 19.
    Uso de maplong aux; map<long,int> raiz; raiz[4] = 2; raiz[1000000] = 1000; std::cin >> aux; if( root.count(aux) != 0 ) std::cout << root[l] else std::cout << &quot;Nao tem raiz perfeita!&quot;;
  • 20.
    Uso de map#include <map> double bancaSaoJoao( const caipira& caipa ) { map<char*,float,ltstr> preco; char item[20]; double conta = 0.0; price[&quot;carapinha&quot;] = 0.75; preco[&quot;quentao&quot;] = 1.5; preco[&quot;pinhao&quot;] = 1.25; preco[&quot;pipoca&quot;] = 0.75; while( std::cin >> item ) { item = caipa.whatYouWantBaby(); conta += price[item]; } return conta; }
  • 21.
    Uso de map#include <map> struct ltstr { bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) < 0; } }; double bancaSaoJoao( const caipira& caipa ) { map<char*,float,ltstr> preco; char item[20]; double conta = 0.0; preco[&quot;carapinha&quot;] = 0.75; ...
  • 22.
    Uso de mapint main() { map<const char*, int, ltstr> months; months[&quot;january&quot;] = 31; months[&quot;february&quot;] = 28; months[&quot;march&quot;] = 31; months[&quot;april&quot;] = 30; months[&quot;may&quot;] = 31; months[&quot;june&quot;] = 30; months[&quot;july&quot;] = 31; months[&quot;august&quot;] = 31; months[&quot;september&quot;] = 30; months[&quot;october&quot;] = 31; months[&quot;november&quot;] = 30; months[&quot;december&quot;] = 31; cout << &quot;june -> &quot; << months[&quot;june&quot;] << endl; map<const char*, int, ltstr>::iterator cur = months.find(&quot;june&quot;); map<const char*, int, ltstr>::iterator prev = cur; map<const char*, int, ltstr>::iterator next = cur; ++next; --prev; cout << &quot;Previous (in alphabetical order) is &quot; << (*prev).first << endl; cout << &quot;Next (in alphabetical order) is &quot; << (*next).first << endl; }
  • 23.
    Iterators Declaração Identificaçãodo container. list<int> lst; list<int>::iterator li; Acesso ao início da lista: li = lst.begin(); Acesso ao fim da lista: li = lst.end(); Acesso ao elemento int aux; aux = *li;
  • 24.
    Iterators Permite “passear”nos containers list<int> lst; list<int>::iterator li; for( li = lst.begin() ; lst != lst.end() ; lst++ ) std::cout << *it << std::endl; // também pode: li = lst.begin(); *li = 313;
  • 25.
    Algoritmos Permitem percorrercontainters executando operações pré-definidas Existem vários, diversos e variados. Exemplo list<int> lst; vector<int> vet; copy(lst.begin(), lst.end(), vet.begin()); copy(lst.begin(), lst.end(), ostream_iterator<int>(cout, &quot;,&quot;)); sort(lst.begin(), lst.last() );
  • 26.
    Criando classes paraserem incluidas em containers Obrigatório: Definir o operador de cópia: operator=(const T&) Implementar o construtor default: T() Implementar o construtor de cópia: T(const T&) Caso o container desejado seja ordenado, ex: map<> Deve ser definido o operador “menor-que”: operator<() Alguns tipos primitivos possuem: int, char, string Outros não: char *
  • 27.
    Exemplo de tipodefinido pelo usuário Agenda de nomes struct Nome { char* prenome; char* sobrenome; bool operator<(const Nome& n) { return strcmp(prenome, n.prenome) < 0; } } map<Nome,int> agenda;
  • 28.
    Cuidados Acesso àposição inválida de vector<> . vector<int> v; v[100] = 1; // Ups! Solução: Utilizar a interface prevista: push_back() reserve() capacity() Pré-alocar no construtor.
  • 29.
    Cuidados Cuidar paranão criar elementos no map<> de forma inadvertida if( toto[&quot;bob&quot;] == 1 ) ... Se bob não existia em toto , agora existe! Evite utilizando count() para verificar se a entrada existe. if( toto.count(&quot;bob&quot;) ) ...
  • 30.
    Cuidados Utilizar ainterface de serviços observando o desempenho: Exemplo: empty() em list<> . Muito lento if( lst.count() == 0 ) { ... } Bem mais rápido if( lst.empty() ) {...} Como saber? Estudando a STL...
  • 31.
    Cuidados Utilizar umiterador invalidado list<int> lst; list<int>::iterator li; li = lst.begin(); lst.erase(li); ++li; // Ups! Utilizar o retorno do erase para avançar li = lst.erase(li); // Ok!
  • 32.
    Erro de compilaçãocomum! Erro de compilação comum! vector<vector<int>> vet; Falta de espaço! O analisador léxico entende como right-shift.
  • 33.
    Muitos outros containersset , multiset , multimap queue , priority_queue stack , deque slist , bitset , valarray