logo
Contato | Sobre...        
rebarba rebarba

Rodrigo Strauss :: Blog


Tutorial de STL, parte 2: Containers

Containers são objetos que contém outros objetos, como listas, pilhas, filas, etc. Os suporte a containers é um dos pilares da STL.

O primeiro container que veremos - e também o mais simples - é o vector. Ele funciona de forma muito parecida com a array comum do C, com algumas diferenças básicas: o gerenciamento de memória é automático, seu tamanho pode ser modificado durante o tempo de execução, e quando você passa um std::vector como parâmetro a informação de tamanho não se perde. Isso sem contar as facilidades...

Como um trecho de código vale mais do que uma porta de avião caindo, vamos a ele:


#include <iostream>
#include <vector>
#include <assert.h>
 
using std::cout;
using std::endl;
 
int main(int argc, char* argv[])
{
  std::vector<int> v1(10);
  std::vector<int> v2;

 
  cout << "tamanho inicial de v1:" << v1.size() << endl;
  cout << "tamanho inicial de v2:" << v2.size() << endl;

 
  cout << "um item de v1" << v1[5] << endl;
 
  for(int a = 0 ; a < 10 ; a++)
    v2.push_back(a);

  cout << "novo tamanho de v2:" << v2.size() << endl;
 
  // exclui o último item do vector, reduzindo seu tamanho em 1
  v1.pop_back();

  cout << "um item de não existente em v2:" << v2[15] << endl;
 
  // a memória é contígua, como no array
  assert(&v2[5] - &v2[4] == 1);
  assert(((char*)&v2[5]) - ((char*)&v2[4]) == sizeof(int));
 

 
  return 0;
}

Algumas coisas merecem explicações, vamos à elas. O vetor v1 foi alocado da mesma forma que um array C, só que como ele é um objeto o tamanho é passado no construtor. A diferença mais notória entre o array e o vector é que os valores do vector são inicializados com zero. Na realidade, o que acontece é que o objetos criados no vector, são inicializados usando o seu construtor default. E o construtor default do tipo int inicializa a variável com 0. Um exemplo é o seguinte trecho de código:


  int x = int();
  std::cout << x << std::endl

O código acima mostra que a variável x tem valor 0.

Outra coisa notória é que, da mesma forma que um array C, é possível acessar um item com índice maior do que o tamanho do vector, usando o operador []. No código de exemplo eu acesso o item 15 de um vector que tem tamanho 10, e isso não gera exceção (mas, é claro, gera problemas). Nenhum container STL faz verificação de limite de tamanho usando o operador [], cabe ao programador verificar isso antes do acesso. Isso funciona dessa forma para que o acesso aos containers STL fique (quase) tão rápido quanto o acesso a um array. Filosofia C++: você só paga por aquilo que você usa. Caso você queira verificação de tamanho durante o acesso, o vector provê o método at(), que dispara um exceção caso o índice esteja além dos limites do container.

O método push_back(), encontrado em vários containers, adiciona um item no final do container, aumentando o seu tamanho em um item. Após o loop do código acima, o método size() do container retornará 10. Da mesma forma, o método pop_back() exclui o último item do array, reduzindo seu tamanho em 1.

Cada container STL tem suas característica particulares, e as do vector são basicamente:

  • suporte a acesso linear e aleatório dos elementos;
  • tempo constante para inserção e remoção de elementos no final do container;

Para mais informações veja a Referência do std::vector no site da SGI.


Em 16/08/2006 23:51, por Rodrigo Strauss


  
 
 
Comentários
Wanderley Caloni | website | em 17/08/2006 | #
Ao mesmo tempo que a classe vector da STL mantém a filosofia da perfomance, ela fornece um método mais seguro, o "at", que faz a mesma coisa que o operador de subscrito, porém verifica se o índice passado não está fora do limite de dados. Caso esteja fora, lança a exceção out_of_range:

std::vector<int> v(5);

for( int i = 0; i < 10; ++i )
{
try
{
std::cout << v[i] << endl;
}
catch(std::out_of_range& e)
{
cout << "Ops!" << endl;
break;
}
}
Rodrigo Strauss | website | em 17/08/2006 | #
Valeu, corrigido. Só que no seu exemplo de código você esqueceu e usou o operador [] ao invés do at() :-)
Wanderley Caloni | website | em 18/08/2006 | #
Ehehehheheheh foi pra ver se estava esperto =P

Também temos que considerar que o código acima está naquela licença em que eu não me responsabilizo por quaisquer problemas que você venha a ter ao utilizá-lo =)

[]s
Andrea | em 15/09/2006 | #
Olá Rodrigo

Eu gostei muito do seu tutorial, ele já tem continuação ?
A parte 3 ? Tô aguardando.

Ate logo

Andrea
Rodrigo Strauss | website | em 15/09/2006 | #
Sim, já está no forno. :-)
Guilherme | em 06/10/2006 | #
tem como usar o vector com uma classe?
tipo, vector<Pessoa> p...

inté.
Rodrigo Strauss | website | em 06/10/2006 | #
Sim, sem problemas.
Flavio T. Tajiri | em 23/05/2008 | #
Olá! gostei muito dos tutoriais, está de parabéns... porém estou com uma dúvida... Copiei o código da mesma forma que está descrito no tuto, ele compila normalmente mas ao executar, dá erro justamente na parte de buscar um elemento fora do vector. Usando o operador[] ele verificou o tamanho do vector e acusou o erro out_of_range, exatamente o oposto do que foi explicado. Como é possível?

Estou usando o Visual Studio 2008 Express.
Marcos V. | em 04/02/2009 | #
Bom, eu também uso o visual C++ Exress, como você está executando o programa compilado dento do VC++ ele aponta o problema. Agora, se você for no executável e usa-lo vai receber aquela janelinha "O <executavel>.exe encontrou um problema e precisa ser fechado" ou seja, um bug. para evitar isso existe a função at().

Espero estar correto, caso contrário me corrijam. Os tutoriais estão ajudando muito, parabéns Strauss.
Guga | em 17/10/2011 | #
Rodrigo, no trecho de código abaixo vc comete um erro em tentar acessar um valor que vc ainda n adicionou, vc reservou 10 elementos pro vector mas n adicionou nada, ou seja, ele está vazio rs.

cout << "um item de v1" << v1[5] << endl;
Rodrigo Strauss | website | em 18/10/2011 | #
Guga, o trecho está correto. Note que na declaração do vetor eu passo o número 10 no construtor. Isso inicializa o vetor com tamanho 10.

Todos os valores são inicializados dentro do vetor com o construtor padrão, o que faz com que o int fique com valor zero.
rebarba rebarba
  ::::