Smart Pointer – Introdução

Maio 29, 2008

Smart Pointers (ou ponteiros inteligente) são objetos em C++ cuja a função básica é monitorar ponteiros e desalocar os mesmos (dando um delete) quando estes não são mais utilizados. Mas como um Smart Pointer sabe a hora de destruir um objeto? Isso depende da implementação, algumas das técnicas utilizadas são:

  • Contagem de referencias: Para cada alocação de memória, o smart pointer aloca um outro objeto que ele usa para contar quantos smart pointers apontam para a mesma região de memória, esse objeto é compartilhado entre todos os smart pointers que utilizam a mesma região de memória. Sempre que um novo smart pointer passa a apontar para uma região de memória, ele incrementa esse contador, quando ele é destruído, decrementa o contador. O ultimo smart pointer destruído (aquele que decrementar um contador e este chegar a zero) se encarrega de desalocar a memória.
  • Controle de escopo: Essa implementação é a mais simples, ela se baseia no fato que todo objeto em C++ no final da sua vida, tem seu destrutor executado. Os ponteiros que fazem controle por escopo, simplesmente no seu destrutor destroem a região de memória para qual apontam. Esse tipo de ponteiro é apenas utilizados para controlar objetos que não costumam ser compartilhados, como por exemplo alocar um buffer dentro de uma função ou uma classe que possui como membro um objeto que precisa ser alocado dinamicamente.

Funcionamento Básico

Um smart pointer tira proveito do fato que todo objeto em C++ criado na pilha vai ter seu destrutor executado, tirando proveito dessa funcionalidade podemos criar o código a seguir:


class IntPointer
{
    public:      
        IntPointer(int *p):pValue(p) {assert(p);}
        ~IntPointer(){ delete pValue; }

        int *GetValue() { return pValue; }

    private:
        int *pValue;
};

A classe acima simplesmente é inicializada com um ponteiro para inteiros e no seu destrutor se encarrega de liberar a memória, podendo ser utilizada como no exemplo abaixo: 


int main(int, char **)
{
    IntPointer ptr(new int(5));

    using namespace std;

    cout << "Valor: " << *ptr.GetValue() << endl;

    return(0);  

}

 

Criando uma Classe Genérica

Note que no código anterior não nos preocupamos em desalocar a memória alocada no inicio da função. Mas existe um problema: E se quisermos armazenar floats ou qualquer outro tipo de dado? Podemos modificar o código com o uso de templates para que fique genérico:


template <typename  T>
class Pointer
{
    public:
        Pointer(T *p): pValue(p) {assert(pValue);}
        ~Pointer() { delete pValue; }

        T *GetValue() {return pValue; } 

     private:
        T *pValue;
};

Agora podemos usar o código acima com qualquer tipo de dado primitivo, voltando ao exemplo anterior:

int main(int , char **)
{
    Pointer<int> ptr(new int(5));
    Pointer<float> ptrf(new float(5.3f));

    using namespace std;<span> </span>
    cout << "Valor: " << *ptr.GetValue() << endl;
    cout << "Valor float: " << *ptrf.GetValue() << endl;  

    return(0);
}

A classe Pointer ainda não é tão inteligente assim, mas podemos também usar tipos de dado mais complexos:

struct Person
{
    std::string name;
    int age;
};

int main(int , char **)
{
    Pointer<Person> ptr(new Person());

    ptr.GetValue()->name = "SmartPointer";

    using namespace std;
    cout << ptr.GetValue()->name << endl;

    return(0);
};

Sobrecarga de Operadores

Um item inconveniente da classe Pointer é o fato de que é necessário chamar o método “GetValue” sempre que é preciso acessar o ponteiro que ela armazena. Para abstrair isso, podemos usar sobrecarga de operadores e modificar o ponteiro para que ele fique um pouco mais esperto:

template <typename  T>
class Pointer
{
    public:
        Pointer(T *p): pValue(p) {assert(pValue);}
        ~Pointer() { delete pValue; }

        T *operator->()
        {
            return(pValue);
        }

    private:
        T *pValue;
};

//Agora podemos escrever:
int main(int , char **)
{
    Pointer<Person> ptr(new Person());

    ptr->name = "SmartPointer";

    using namespace std;
    cout << ptr->name << endl;

    return(0);
};

Conclusão

Com essa pequena classe temos uma implementação bem simples de um smart pointer (ela tem alguns problemas, como não tratar const corretamente, não funciona se o objeto pointer for copiado, arrays, etc), sendo assim, esta classe não serve para muita coisa a não ser como exemplo simples (digamos que não podemos chamar ela de smart).

Um detalhe interessante é que usando corretamente inlines e compilando o código acima em um bom compilador (com otimizações ligadas) usar essa classe de Pointer não traz sobrecarga nenhuma ao programa, não teremos nenhum custo adicional de performance ou consumo de memória usando esse tipo de construção. No Visual Studio, por exemplo, a classe inteira desaparece com otimizações ligadas, ficando apenas a chamada de delete que desaloca a memória.

Por hoje é apenas isso, mas no próximo post, vamos ver uma classe de smart pointer que faz parte da biblioteca padrão do C++: auto_ptr.

Próximo artigo da série: Auto Pointer (auto_ptr)


Compilando a Boost no Windows (usando Visual Studio)

Maio 14, 2008

Este artigo esta desatualizado, para a versão mais recente clique aqui

Como pretendo falar um pouco sobre o uso de smart pointers, e pretendo fazer isso utilizando as implementações existentes na Boost, então o primeiro passo é instalar a Boost.

Mas primeiramente, o que é a Boost? A Boost é uma coleção de bibliotecas para o C++ desenvolvido por diversas pessoas, seguindo rigorosos critérios de qualidade e portabilidade, sendo que é possível utilizar a Boost na maioria dos compiladores modernos. A Boost reúne bibliotecas como:

  • Smart Pointers
  • Tipos Variant
  • File System
  • Operações com Imagens
  • Threads
  • e muito mais…

Para melhores informações, acesse o site da Boost, e aproveite e já faça download do pacote com o código.

A seguir vamos ver como compilar a Boost (note que para usarmos alguns componentes da Boost, como smart pointers, não é necessário compila-la, mas porque não aproveitarmos a oportunidade e deixar tudo pronto?)

Para as instruções abaixo, estou assumindo que o usuário possui um Visual Studio instalado (e no caso das versões Express, possui a Platform SDK instalada) 

Configurando o Environment

Caso você não use as versões express do Visual, pode pular essa parte. Caso contrário, é necessário configurar algumas variáveis de ambiente antes de prosseguir. No Windows, clique em Iniciar -> Painel de Controle -> Sistema. Escolha a TAB avançado, e clique em variáveis de ambiente. Na parte de variáveis do sistema, procure por “INCLUDE”. 

Caso não exista, clique em “Novo” e entre com os dados:

Nome: INCLUDE

Valor: C:\Arquivos de Programas\Microsoft Platform SDK for Windows Server 2003 R2\Include

Tenha certeza, que o caminho é o caminho valido para a Platform SDK instalada em sua maquina, e inclua o diretório Include.

Caso a variável já exista, clique em “Editar”, na parte do valor, vá para o final e entre com o mesmo valor usado acima, mas inclua  um “;” antes, exemplo:

Valor: c:\develop\libs\loki\include;C:\Arquivos de Programas\Microsoft Platform SDK for Windows Server 2003 R2\Include

Criada a variável INCLUDE, é preciso então criar a variável LIB, basta seguir o o mesmo procedimento acima, e no valor entre:

C:\Arquivos de Programas\Microsoft Platform SDK for Windows Server 2003 R2\Lib

Novamente, tenha certeza de que o valor acima é o correto para o seu sistema. Vá clicando em “OK para salvar as configurações e vamos continuar.

Compilando

Após baixar o código, descompacte o arquivo para o seu diretório de libs (caso não tenha um ou não sabe o que é isso, basta criar um diretório qualquer em seu computador que você deve utilizar para as bibliotecas). No meu caso, a Boost é descompactada para c:\develop\libs\, resultando em c:\develop\libs\boost_1_35_0. 

Após descompactar os arquivos, é necessário copiar o Bjam, que é a ferramenta usada para compilar a boost. O Bjam pode ser encontrado no site da Boost. Após copiar o Bjam (a versão executável, se você baixou o código apenas, vai ter que compila-lo antes de usar). Descompacte o Bjam e coloque no mesmo diretório de instalação da Boost (no meu caso c:\develop\libs\boost_1_35_0).

Tendo instalado o código e o Bjam, é hora de acessar o prompt de comando do Visual Studio, basta clicar em Iniciar -> Programas -> Visual C++ 2005 Express Edition -> Visual Studio Tools -> Visual Studio 2005 Command Prompt. Note que esse é o caminho para Visual Studio 2005 Express, se você usa alguma outra versão, o caminho vai variar, mas o importante é acessar o prompt de comando do Visual, não o padrão do Windows.

Dentro do prompt, basta ir para o diretório da Boost (no meu caso, digitando: cd develop\libs\boost_1_35_0), chegando no diretório, precisamos chamar o Bjam passando como parâmetro o toolset a ser usado (no caso do visual, msvc), mas antes é preciso saber a versão do visual:

  • Visual Studio Express 2005 ou Visual Studio C++ 2005: 8.0
  • Visual Studio Express 9.0: 9.0

Agora basta invocar o Bjam usando o toolset e a versão correta:

  • Visual 2005: bjam toolset=msvc-8.0
  • Visual Studio 2009: bjam toolset=msvc-9.0

E esperar … 

Após concluído o build a Boost esta pronta para ser usada. 

No próximo post vou começar a mostrar como usar os smart pointers da boost e outros componentes.


Wincatalog 2008

Maio 7, 2008

Se você é como eu e possui dezenas de CDs e DVDs cheios de arquivos, artigos, samples, códigos, libs, tools, etc; e sempre quando você precisa de algum desses arquivos nunca consegue encontrar o maldito CD, ou simplesmente tem preguiça de ficar procurando em todos os CDS (porque muitas vezes é mais fácil baixar de novo o arquivo). Então instale o WinCatalog 2008!

Este programa permite que você cadastre todos os seus CDs, DVDs, disquetes (alguem ainda usa isso?), e feito o cadastro, possui um sistema de busca, que facilita muito a vida na hora de procurar aquele arquivo sumido. Identificado o CD, você pode então pegar ele na pilha (estou assumindo que você ao menos numerou os seus CDs) e copiar o arquivo!

Tem a versão light que é totalmente free, mas a versão 2008 (que na verdade é free se você utilizar apenas para avaliação, limitado a 5 volumes por arquivo) tem muito mais recursos:

  • Pastas virtuais: com isso você podem organizar todos os seus arquivos em uma estrutura de diretório única, achei bem útil isso, é como se todos os arquivos estivessem juntos.
  • Objetos pessoais: você pode criar outros objetos para armazenar, como por exemplo, sua lista de livros (de papel) dentro do programa, para que? Simples, você pode cadastrar seus amigos e gerenciar empréstimos!
  • Processa arquivos zip: ele permite que você veja o que tem dentro daqueles arquivos zip com nomes estranhos que você guardou a 5 anos atrás sabe la deus porque!

Caso queira experimentar: http://www.wincatalog.com/standard.html


Valve Steamworks

Maio 2, 2008

Steamworks

A Valve Software liberou esse semana a API do Steamworks, que é uma API que pode ser usada para:

  • Coletar estatísticas do jogo (como por exemplo média de pontos de um jogador)
  • Autenticação para Multiplayer
  • Controle de partidas (Matchmaking)
  • Gerenciar comunidade
  • Rede (vide sockets :) )
  • Sistema anti-chear
  • Comunicação por voz
  • DRM (Digital Rights Management ou controle de pirataria)

Pelo site tudo é de graça e qualquer um pode utilizar, não vi ainda as entre linhas e nem testei, mas parece interessante: https://partner.steamgames.com/