PontoV e o Blog

novembro 6, 2009

Hoje foi inaugurado o PontoV, que é o mais novo portal brasileiro sobre desenvolvimento de jogos. O portal surgiu de uma parceria minha com o Vinícius do PontoV (http://vinigodoy.wordpress.com).

O nosso objetivo no portal é compartilhar nossas experiências em gamedev e reunir os desenvolvedores brasileiros.

O nosso foco principal é trazer conteúdo de qualidade sobre GameDesign, Java e C++, além de artigos de profissionais da área.

A principio não sei ao certo qual será o futuro do blog, pois tópicos sobre programação vão acabar sendo destinados ao PontoV, então estou aberto a sugestões :) .

De qualquer forma nos vemos no PontoV: http://www.pontov.com.br


Matrizes Dinâmicas

agosto 25, 2009

Voltando um pouco as bases vamos analisar neste artigo algumas possibilidades para criação de matrizes dinâmicas usando C++. Tem sido bem comum em fóruns e listas de emails o pessoal dar cabeçada com esse problema, neste artigo vou apresentar as soluções mais conhecidas e as características de cada uma.

Alocando cada Linha

A técnica que parece ser a mais popular é alocar um vetor de ponteiros e depois alocar uma linha da matriz para cada ponteiro deste vetor:


int main(int, char **)
{
    int nlinhas = 5;
    int ncol = 5; 

    int **mat = new int*[nlinhas]; 

    for(int i = 0;i < nlinhas; ++i)
        mat[i] = new int[ncol]; 

    //iniciando ela com zero
    for(int i = 0;i < nlinhas; ++i)
        for(int j = 0;j < ncol; ++j)
            mat[i][j] = 0; 

    //liberar memória
    for(int i = 0;i < nlinhas; ++i)
        delete []mat[i]; 

    delete []mat; 

    return 0;
}

O problema dessa técnica é o grande desperdício de espaço e tempo que ela gera. O desempenho desta é o pior, principalmente pelo fato de serem necessárias varias alocações e alocações de memória em C/C++ são operações que costumam ser bem caras.

Mesmo ignorando o tempo de criação da matriz, o uso dela também vai ser comprometido devido a possibilidade de cada linha dela estar numa região de memória diferente e é bem provável que o cache do processador tenha dificuldades em se manter atualizado por causa disso.

Já o desperdício de espaço ocorre devido a necessidade de se realizar varias alocações e é comum cada alocação precisa alocar um pouco mais de espaço do que o requisitado para a estrutura de controle usada internamente para gerenciar a memória.

A única vantagem em utilizar este método é quando precisamos de uma matriz absurdamente grande e alocamos cada linha apenas quando existe necessidade, mas mesmo nesse caso acredito que existam técnicas melhores para se implementar uma matriz esparsa.

Usando Apenas um Vetor

Uma maneira mais simples de se implementar uma matriz é utilizando apenas um vetor e realizar o acesso dos elementos como se fossem uma matriz:


int main(int, char *argv)

int main(int, char **)
{
    int nlinhas = 5;
    int ncol = 3; 

    //alocando a "matriz"
    int *mat = new int[nlinhas * ncol]; 

    //colocando 5 na linha 3, coluna 2
    mat[3 * ncol + 2] = 5; 

    //liberando a memoria
    delete []mat; 

    return 0;
}

Note como o código nesse caso é muito mais simples que o anterior, o único incomodo deste código é a necessidade de armazenar o tamanho da matriz (o número de linhas para ser mais preciso) e ficar passando ele como parâmetro a todo momento na hora de acessar um elemento, mas não é nada complicado criar uma classe para encapsular isso.

Para acessar um elemento usamos a fórmula: elem[linha * ncol + col], onde linha é o numero da linha que se quer acessar, ncol o número de colunas da matriz e col o número da coluna que se deseja acessar.

Como é feita apenas uma alocação é usado o minimo de memória possível, além de deixar o cache feliz na hora de acessar os dados.

Utilizando std::vector

Por fim, podemos utilizar o std::vector e não precisamos assim nos preocupar mais em gerenciar a memória da matriz e deixar o programa mais alinhado com o RAII:


#include <iostream>
#include <vector>

int main(int, char **)
{
    int ncol = 4;
    int nlinha = 3; 

    std::vector mat(ncol * nlinha);    

    //acessando elemento 2, 1 (linha 2, coluna 1)
    mat[2 * nlinha + 1] = -1; 

    std::cout << mat[2 * nlinha + 0] << std::endl;
    std::cout << mat[2 * nlinha + 1] << std::endl; 

    return 0;
}

Esse código é muito semelhante ao anterior, mas as operações de gerenciamento de memória foram encapsuladas com o uso de um std::vector, utilizando-se uma boa implementação de std::vector não deve existir diferença alguma de performance e uma diferença minima de consumo de memória entre este exemplo e o anterior.

Esta é a maneira mais simples que conheço para lidar com matrizes dinâmicas, mas o ideal mesmo seria construir uma template que encapsule estas operações, mas isto fica para um outro post.


Problemas com Memória

julho 21, 2009

Neste artigo vamos discutir dois problemas comuns e causam um bocado de dores de cabeça e as vezes fazem a gente perder preciosas horas de sono, vamos então conhecer os memory leaks e dangling pointers.

Memory Leaks

Memory leak ou vazamento de memória é um problema um tanto comum em C++, principalmente em casos onde o programador tende alocar memória sem necessidade (o que tem se tornado bem comum com programadores que vem de linguagens onde existe um garbage collector) ou não gerencia esta corretamente esquecendo os princípios básicos do RAII.

O memory leak ocorre quando um bloco de memória alocado fica sem referências, isto pode ocorrer em programas bem simples, vejamos um exemplo:


int main(int , char **)
{
    int *p = new int;
    *p = 3; 

    p = new int;
    delete p; 

    return 0;
}

No exemplo acima, primeiramente é alocado espaço para um int e associado com o ponteiro p, logo após a atribuição do valor “3” é feita uma nova alocação e é neste ponto que o vazamento ocorre.

Note que a memória alocada anteriormente não foi liberada e agora o ponteiro p aponta para outro bloco de memória, a única variável que continha o endereço do primeiro bloco alocado não possui mais, sendo assim, o programa não sabe mais o endereço do bloco e não tem mais como liberar essa memória.

No final da execução desse programa o sistema operacional vai se encarregar de liberar toda a memória do programa, sendo assim este pequeno int que foi perdido não é problema, mas imagine o caso de um programa que tenha que funcionar em um regime 24×7, e a cada segundo ele perde uma centena de ints como aquele, nesse ritmo o programa perde 400 bytes por segundo (não contando aqui o overhead da alocação, que inclui as estruturas de controle do runtime do C++ e do SO).

Em uma hora este programa já vai ter perdido pouco mais de 1 mega de memória, em 24 horas já vão embora 32 mega de memória. Não parece grande coisa, ainda mais hoje em dia que até computador das Casas Bahia vem com 2 gigas de memória, mas lembre-se que esta memória poderia estar sendo útil para outros processos, e no caso de um sistema embarcado este problema é bem grave, um playstation 2, por exemplo, possui apenas 32 mega de ram, então em uma hora já acabamos com boa parte da memória dele.

Dangling Pointers

Os ponteiros “quebrados” costumam ser bem desastrosos e ocorrem quando um ponteiro aponta para uma região de memória “invalida”. Na verdade o ponteiro apontar para algo invalido não é problema, o problema ocorre quando é feita uma tentativa de acesso nesse endereço invalido, vamos a um exemplo básico:


#include <string> 

void func()
{
    std::string *str = new std::string("abc");
    delete str; 

    str->assign("bla bla");
} 

std::string *func2()
{
    std::string str; 

    return &str;
} 

int main(int , char **)
{
    func(); 

    std::string *str = func2();
    str->assign("ops");

    return 0;

}

A primeira função (a func) primeiramente aloca uma std::string, libera ela da memória e depois disso tenta acessa-la. Este é o caso mais comum de um dangling pointer, onde um ponteiro armazena um endereço para um bloco de memória que já foi liberado. Nesse exemplo é muito provável que nada demais aconteça pois o uso é feito logo após a desalocação, mas não podemos esquecer que após um delete estamos dizendo ao sistema que não vamos mais usar aquela memória e ele pode fazer o que bem entender com ela, isso significa que esta memória pode inclusive ser devolvida ao sistema operacional, que pode passar ela a outro processo, sendo que tudo isso pode acontecer antes mesmo da chamada de assign, e quando assign for executado ele vai tentar acessar a memória de outro processo e teremos um belo “ding, este processo executou uma …”.

Em programas mais complexos pode ser que ocorram novas alocações de memória antes que o dangling pointer seja usado, nesse caso aquele bloco que foi liberado já pode estar sendo usado por outro objeto e na chamada de assign estaremos acessando uma memória que pode conter qualquer valor, onde o resultado da operação é como diz a especificação “indefinido”.

A função func2 mostra um outro erro bem comum onde retornamos o endereço de uma variável local, nesse caso após a função retornar o destrutor da string vai ser chamado e sem falar que o endereço que ela “reside” já vai estar disponível para outros usos, novamente é bem provável que o sistema operacional se zangue com seu processo e mate ele.

Um detalhe sobre a segunda função é que muitos compiladores geram um warning quando o programador faz algo desse tipo, sendo assim este problema é fácil de ser evitado.

Evitando Esses Problemas

O jeito mais simples de evitar estes problemas é utilizar alguma técnica de smart pointer, com isso já é possível evitar os memory leaks (tem que apenas tomar cuidado com as referencias circulares).

Utilizando smart pointers é certo que um dangling pointer nunca vai ocorrer pois o smart pointer vai cuidar para que os ponteiros sejam sempre válidos (claro que pode ocorrer uma invasão de memória ou outro evento grotesco).

Infelizmente os memory leaks ainda podem ocorrer devido as referencias circulares e para tentarmos detectar estes precisamos usar outras técnicas, mas isto fica para um próximo post.


Mapa do C++

junho 15, 2009

Este semana rolou um email bem legal na lista de emails cppbrasil, o email continha o link para um mapa do C++ no estilo usado em mapas antigos:

O post original do mapa pode ser encontrado clicando-se aqui, inclusive contem opções de tamanho.


Compilando a Boost no Visual – 2009

junho 3, 2009

O primeiro post do blog foi exatamente este, e não querendo já parecer sessão da tarde e começar a repetir tudo de novo estou re-fazendo o post.

O post original é bem incompleto em vários aspectos, e ao invés de atualizar ele decidi fazer um completamente novo aproveitando que estou configurando uma maquina de build.

Outra vantagem deste artigo é que indo direto a seção “Configurando o Visual”, as informações ali contidas servem para a maioria das bibliotecas de C/C++.

Baixando a Boost

Esta é a etapa mais simples de todas, basta acessar o site oficial, e clicar no link “Download” do lado direito da tela. A versão 1.39.0 (a ultima lançada até o dia que esse artigo foi publicado) pode ser baixada clicando aqui.

No meu caso utilizo a versão zip do pacote, mas todos os outros pacotes acredito que possuam o mesmo conteúdo.

Após o download extraia o conteúdo dos arquivos para o diretório de bibliotecas que você costuma utilizar, no meu caso c:\develop\libs.

Depois de extrair os arquivos é necessário baixar o bjam, que é a ferramenta de compilação da Boost, a ultima versão pode ser encontrada clicando aqui.

Após concluído o download do bjam extraia o arquivo exe para o mesmo diretório em que a Boost foi colocada  (no meu caso C:\develop\libs\boost_1_39_0).

Compilando

Agora com as ferramentas prontas é necessário rodar o bjam, para tal acesse o console do Visual Studio (não o console padrão do Windows) clicando em “Iniciar” –> Todos os programas –> Microsoft Visual Studio –> Visual Studio Tools –> Visual Studio 2008 Command Prompt.

Com o console aberto abra o diretório da Boost (no meu caso digito: cd \develop\libs\boost_1_39_0). Dentro do diretório da boost digite “bjam” e ENTER.

Agora como já diz o programa, paciência…

Se tudo correu bem, muitos minutos depois a compilação deve estar completa, as vezes aparecem alguns warnings, que eu simplesmente ignoro.

Configurando o Visual

O jeito mais pratico de configurar o visual na minha opinião é criando uma variável de ambiente que contenha o diretório da Boost, fica mais pratico na hora de atualizar as versões (se não quiser criar a variável, basta ir para o próximo paragrafo), então primeiramente clique em “Iniciar” –> Botão direito em “Meu Computador” –> Propriedades.  Na janela que se abrir, clique em “Avançado”, depois no botão “Variáveis de Ambiente”. Na caixa “Variáveis do Sistema”, clique em “Novo”. Agora entre com o nome (ex: BOOST_HOME), e o valor, que é o diretório onde a boost foi instalada (c:\develop\libs\boost_1_39_0 no meu caso), agora é ir clicando em Ok até fechar tudo.

O próximo passo é abrir o visual (se o seu visual já estava aberto e você criou a variável, feche ele e abra novamente). Dentro do visual acesse “Tools” –> “Options”, expanda a linha “Projects and Solutions” –> “VC++ Directories”.

Com a janela de configuração de diretórios podemos configurar os diretórios utilizados pelo visual durante builds, o primeiro a ser configurado é o de include (a ordem não importa aqui), então do lado direito, na caixa de seleção “Show directories for”, selecione “Include Files”. Basta clicar na primeira linha vazia após o ultimo item e entrar com o diretório, que no meu caso foi: $(BOOST_HOME). Caso eu não tivesse criado a variável, o valor teria sido: c:\develop\libs\boost_1_39_0.

Configurando diretórios de include

Por fim é necessário configurar o diretório de bibliotecas selecionando “Libraries Files” na caixa “Show Directories for” e entrando com o diretório das libs, que no meu caso foi: $(BOOST_HOME)\stage\lib, se não estiver usando a variável, basta então: c:\develop\libs\boost_1_39_0\stage\lib, note que o diretório varia de acordo com o diretório que foi usado na instalação, mas o principal é o sub-diretório “stage\lib”.

visual_boost_02

Tendo inserido os diretórios, clique em Ok para salvar.

Testando a Instalação

Para testar a instalação crie um novo projeto no Visual (se não sabe como fazer, clique aqui) e use um código exemplo da Boost, eu utilizei o código abaixo:


#include<boost/filesystem/operations.hpp>
#include<iostream>

namespace bf = boost::filesystem;
int main(int, char **)
{
    bf::path p("first.cpp");
    if(bf::exists(p))
        std::cout<<p.leaf()<<"exists.\n";
    else
        std::cout<<p.leaf()<< "does not exist.\n";

    return 0;
}

O código compilou sem problemas aqui e executou perfeitamente, sendo assim, instalação concluída.

Note que a Boost automaticamente já linka o código com as bibliotecas necessárias, com algumas bibliotecas é necessário configurar o arquivo lib a ser usado, mas isso fica para outro post.


Boost 1.39.0

maio 4, 2009

Foi lançada a mais nova versão da Boost, desta vez inclui apenas uma lib nova, a Signals2, que é uma implementação de um sistema de sinais e slot, na verdade essa lib é uma implementação thread safe da Signals já existente. Além desta lib nova foram feitas diversas correções e melhoramentos nas libs existentes, maiores detalhes no release notes.


Como Utilizar o Visual Studio C++ – Parte 3

abril 22, 2009

No artigo anterior vimos de maneira mais detalhada como realizar um build no Visual e diversas configurações, agora vamos expandir um pouco mais nosso ambiente instalando a Windows SDK, que consiste num kit de desenvolvimento para aplicações Windows.

Pode ser que seu projeto não precise utilizar a API do Windows diretamente, mas outras libs podem precisar (Boost por exemplo).

Baixando a SDK

Para baixar a SDK basta acessar o link de download: Windows SDK for Windows Server 2008 and .NET Framework 3.5, para baixar uma imagem de DVD ISO com toda a SDK, use esse link.

No meu caso optei por instalar a versão web, pois como não utilizo todos os componentes não preciso fazer todo o download.

Após o donwload do programa setup, basta rodar ele. Surge então a primeira tela do setup, clicando em next ele pergunta sobre os diretórios de destino (no meu caso, uso o valor padrão).

Em seguida o instalador pergunta sobre os componentes a instalar, no meu caso dispenso qualquer coisa relacionada a desenvolvimento 64 bits (minhas maquinas são todas 32 bits), dispenso também os samples (exemplos) e documentação (que pode ser vista online), minha configuração ficou:

visual_p3_setup_sdk_02

As seleções aqui são um tanto pessoais e dependem do que você pretende fazer, mas o principal a instalar são os componentes do Windows Headers and Libraries, incluindo no minimo os “Header Files” e alguma das “Libraries”. Lembre-se que se for incluído apenas as bibliotecas para CPU 64 bits, será possível apenas compilar código para essa arquitetura.

Clicando em “next”, o instalador vai iniciar o download e a instalação logo após a conclusão deste.

A instalação é bem básica, e apos a conclusão basta clicar em “Finish”.

Testando a Instalação

Se tudo correu bem, agora basta pegar o programa “Hello World” do primeiro artigo da série e modifica-lo:

#include <windows.h>

int main(int argc, char **argv)
{
    MessageBox(NULL, L"Ola Windows!", L"Teste", MB_OK);
    return 0;
}

Agora é compilar e executar o programa, durante a execução deve ser surgir uma dialogo com a mensagem definida acima.

No próximo post vou aproveitar e atualizar o artigo de compilação da Boost, que esta incompleto e desatualizado.


Como Utilizar o Visual Studio C++ – Parte 2

abril 1, 2009

No artigo anterior vimos como instalar e como criar um programa de teste no visual, agora vamos nos aprofundar um pouco mais no sistema de build do visual.

Configurações de Build

O visual por padrão possui duas configurações de build, a debug e a release. Cada versão permite que o usuário configure o compilador de maneiras totalmente diferentes, além de ser possível criar quantas configurações forem necessárias.

Estas configurações são uteis para permitir, por exemplo, desabilitar qualquer otimização do compilador e facilitar a depuração de código (fato que já ocorre na configuração Debug gerada quando um projeto é criado), sendo assim, a versão debug é geralmente usada apenas pelos desenvolvedores.

Já a versão release liga as otimizações do compilador e (geralmente) desliga a geração de informações de debug, sendo esta usada para se realizar um build quando queremos enviar o software ao usuário final.

A configuração atual pode ser visualizada no topo da janela do visual, próximo as opções de menu:

Caixa de seleção de configurações.

Na figura acima vemos que a configuração ativa é a Debug, clicando na caixa de seleção é possível alterar a configuração a ser usada no próximo build.

Além das configurações de build, é possível especificar uma plataforma para cada configuração, como por exemplo Win32 e Win64, como nunca trabalhei com desenvolvimento multi-plataforma no visual (nos projetos multi-plataforma que trabalhei usávamos uma IDE para cada ambiente) não vou me aprofundar nesse item.

Opções do Menu Build

Na figura abaixo podemos ver as opções do menu build do visual, que são descritas a seguir:

Menu de build do visual

Vemos que o menu de build é divido em quatro seções, sendo estas:

  1. Solução (solution): comandos que afetam toda a solução.
  2. Projeto: os comandos aqui afetam apenas o projeto e suas dependências.
  3. Lote (Batch): comandos que afetam múltiplas configurações.
  4. Compilar: este compila apenas o arquivo sendo editado.

Note que os comandos de compilação são basicamente:

  • Build: este comando compila apenas os arquivos alterados e as dependências afetadas por estes.
  • Rebuild: este comando apaga todos os arquivos gerados, forçando uma rê-compilação completa.
  • Clean: apenas apaga os arquivos gerados.

Detalhe que os comandos relacionados ao projeto não afetam unicamente o projeto sendo editado, podem afetar as suas dependências, se existirem múltiplos projetos dentro de uma solução, os comandos da seção projeto vão afetar as dependências também, para aplicar o comando apenas ao projeto selecionado, escolha as opções do item “Project Only”. Veremos o uso de dependências em mais detalhes no próximo post.

Opções de Runtime

O runtime (no caso do visual) é a forma como seu projeto é associado a biblioteca padrão do C ou C++ (a libc), que no caso do visual pode ser uma dll, as famosas MSVC???.lib, onde ??? varia de acordo com a versão e tipo de build, ou então, uma lib que é linkada diretamente com seu projeto.

Mas para que especificar uma biblioteca C/C++, não deveriam ser iguais? Sim, deveriam, mas a Microsoft disponibiliza dois tipos básicos, uma versão debug e outra versão release.

A versão debug da libc gera informações extras de depuração que veremos em detalhes no post sobre como usar o depurador do visual, já a versão release não possui essas informações e é construída com todas as otimizações possíveis.

Além da versão debug e release, existem para cada uma delas a versão DLL e não DLL. A diferença entre elas é que na versão DLL, seu código é linkado com a MSVC???.dll, na versão não dll (estática), o seu código é linkado diretamente com o arquivo lib não precisando da dll para ser executado.

Para configurar o runtime sendo usado basta clicar com o botão direito do mouse sobre um projeto, e escolher “Properties”:

menu de um projeto

Na janela que abrir, basta expandir a “Configuration Properties”, depois o item “C/C++”, e clicar em “Code Generation”, do lado deve surgir então o item “Runtime Library”, como na figura abaixo:

Propriedades de um projeto

As opções são:

  • Multi-threaded (/MT): versão release multi thread, essa é a versão para linkagem estática.
  • Multi-threaded Debug (/MTd): mesma anterior, mas versão debug.
  • Multi-threaded DLL (/MD): versão release multi thread, mas para linkagem dinâmica.
  • Multi-threaded Debug DLL (/MDd): mesma da anterior, mas versão debug.
  • inherit from project defaults: este simplesmente usa a configuração de um projeto pai (nesse caso a solução) ou configuração padrão.

Detalhe que todas as libs são especificadas como multi-threaded, isso indica que elas podem ser usadas com código multi-thread (antigamente existia também a opção single thread).

Um detalhe que pode passar despercebido sobre a janela de propriedades é que existe uma versão para cada configuração, a configuração sendo utilizada fica no canto superior esquerdo da janela de configurações.

Escolhendo o Runtime

A escolha do runtime depende muito do tipo de projeto, e a decisão se baseia entre versão DLL ou não DLL, sendo debug e release escolhidos de acordo com o tipo de build.

A versão DLL é recomendada se seu projeto utiliza dlls, isso é necessário porque se o seu projeto usar a versão não dll da libc, cada dll e o exe do seu programa vão ter sua própria heap. Como cada módulo possui sua própria heap, a memória alocada em um módulo (dll ou exe), utilizando new ou malloc, tem quer ser liberada apenas no mesmo módulo, a estrutura do programa fica como no exemplo abaixo:

suposto programa usando libc com linkagem estatica

Já o mesmo programa utilizando a versão da libc para dlls, fica com a estrutura como na figura abaixo:

o mesmo programa usando libc com linkagem dinâmica (dll)

Sendo assim, se seu projeto utiliza dlls, é recomendável linkar ele apenas com a versão dll da libc.

Arquivos Gerados no Build

Na configuração padrão de projetos do visual, ele cria duas sub-pastas uma para os builds de debug, e outra para release:

Estrutura de diretórios de uma solução

Nestas duas pastas são colocados os arquivos gerados durante o build, no caso do build de release do meu programa de testes:

Arquivos gerados pelo build

Exceto por hello.exe, todos os outros arquivos são utilizados apenas pelo visual durante um build. Isso significa que para enviar esse programa para alguem basta enviar o arquivo exe gerado, que é suficiente para este programa funcionar.

Outro detalhe que como o conteúdo destas pastas é todo gerado pelo visual, removendo qualquer um ou todos os arquivos não causa problema algum, basta executar o build que o visual os gera novamente.

O visual permite modificar a pasta usada para armazenar os arquivos gerados e a maneira mais simples consiste em acessar as propriedades do projeto (clicando com o botão direito sobre o projeto no Solution Explorer, e clicando em “Properties”), na janela que abrir, selecione a opção General, que fica dentro de “Configuration Properties”, deve surgir então a opção “Output Directory”, que indica o diretório usado:

Propriedades do projeto, alterando diretórios de saída

O caminho padrão é um pouco estranho, pois consiste de: $(SolutionDir)$(ConfigurationName). Isso na verdade são duas variáveis de ambiente criadas pelo visual, sendo que $(SolutionDir) e $(ConfigurationName) contém respectivamente o diretório da solução e o diretório da configuração sendo usada. Pode-se por exemplo modificar para: $(SolutionDir)\bin, com esta alteração o arquivo exe vai ser ser gerados no diretório bin.

Alterando o valor da opção “Intermediate Directory” modifica o diretório de destino dos arquivos temporários (como arquivos obj).

No próximo post, vamos ver como instalar a Windows SDK no visual.


Como utilizar o Visual C++ – Parte 1

março 6, 2009

O Visual Studio é um pacote de programas da Microsoft para desenvolvimento de software, suportando diversas linguagens como C#, C++, C, Java, Visual Basic, etc. Nesta série de artigos vou focar apenas no Visual C++ Express 2008, mas a maioria da dicas / comandos devem funcionar em outras versões do Visual C++.

As versões express do Visual Studio são versões grátis que a microsoft disponibiliza e obviamente elas não possuem todas as funcionalidades das versões pagas, mas na minha opinião o Visual C++ Express é a melhor ferramenta “grátis” para se trabalhar com C++ no Windows.

Instalando

O primeiro passo é instalar a ferramenta, e o jeito mais simples é indo ao site oficial: Visual C++ Express. Logo ali no lado direito tem um botão “Download Now”, escolha a linguagem (Inglês no meu caso) e clique em Download.

Após concluído o download, execute o programa para inicializar a instalação que a principio é como qualquer outro programa, aceitar licença, instalar algum atalho extra, etc.

A versão atual do instalador pergunta se você quer instalar o Microsoft Silverlight Runtime e o Microsoft SQL Server, nenhum dos dois é necessário, a menos que você queira usar o SQL Server como banco de dados para suas aplicações ou utilizar o Silverlight

Opcionais do Visual C++ Express

Após escolher os adicionais, vem a escolha do diretório de instalação, de novo, é a gosto do fregues. Clicando em “Next” é iniciado o download. Existe no site da Microsoft imagens de CD para quem quiser instalar em um computador que não tenha acesso a rede.

Rodando

Após concluída a instalação, o instalador cria um atalho no menu iniciar, basta então acessar ele e clicar no “Microsoft Visual C++ Express Edition 2008″. O Visual vai carregar e você deve ver uma tela parecida com a abaixo:

Tela inicial do Visual

A versão express costuma solicitar registro, basta seguir o link do dialogo que surgir, entrar com os dados e depois inserir a chave de registro no visual.

Criando a primeira Solução (projeto)

O Visual Studio gerencia o software criado através de soluções, cada solução possui um ou mais projetos, que formam o software ou o conjunto de software sendo criado.

Para criarmos nosso “Hello Visual”, clique em “File” -> “New” -> “Project”. Surge então um dialogo parecido com o abaixo:

Criando novo projeto

Clique em Win32, depois selecione “Win32 Console Application”. Entre com o nome do projeto, diretório onde ele vai ser criado, e nome da solução (que é opcional), em seguida clique em “Ok”.

Configurando o novo projeto

Surge então a primeira tela do Application Wizard, clique em “Next”, na segunda tela selecione “Console Application” e marque a caixa “Empty Project “. Dessa forma é criada uma aplicação vazia, e sem o código de “Hello World” do visual. Depois de criado, o projeto pode ser modificado para aplicação com janela, dll ou biblioteca.

Selecionando o tipo de projeto a ser criado

Agora clique em “Finish” e o projeto vai ser criado.

Após criada a aplicação, deve surgir então o “Solution Explorer”, que é uma janela (que costuma ficar do lado esquerdo da tela) com a visão de todos os projetos e arquivos da sua solução.

Visão do Solution Explorer

No nosso caso ela vai estar vazia, agora criaremos o primeiro arquivo de código: clique com o botão direito do mouse no nome do projeto (meuPrimeiroProjeto, no exemplo), selecione “Add” -> “New Item”. Na janela que aparecer, selecione “C++ File (.cpp)”, entre com o nome do arquivo e clique em “Add”.

Criando novo arquivo para o projeto

Vai surgir então um lindo arquivo em branco, repare no “Solution Explorer” que o arquivo foi adicionado ao seu projeto, agora basta entrar com o código do “Hello World”:

#include <stdio.h>
int main(int argc, char **argv)
{
    printf("Hello Visual");
    return 0;
}

Após entrar com o código, clique na opção “Build” (menu principal) e selecione “Build”, ou então pressione F7. Na parte de baixo da tela vai surgir a tela de output, que mostra o que o compilador esta fazendo, e no final do processo ela indica se houve algum erro ou não. Se aconteceu algum erro, dando um clique duplo sobre a mensagem de erro foca o mesmo na tela.

Programa de teste após compilação

Rodando o “Hello World”

Agora que o projeto já foi compilado, basta executar ele. No menu principal, selecione “Debug” -> “Start Without Debugging”, ou pressione “CTRL + F5″. Pronto, vai surgir uma janela de console com a saída do seu programa.

No proximo post, vamos aprender um pouco mais sobre o build do visual.


Boost 1.38.0

fevereiro 9, 2009

Foi lançado no ultimo dia 8 a versão 1.38.0 da Boost, que além de inúmeras correções de bugs inclui  três novas bibliotecas:

  • Flyweight: uma implementação do design pattern Flyweight, este pattern permite o compartilhamento de dados entre objetos e ele gerencia os dados compartilhados.
  • ScopeExit: permite que seja executado um código qualquer na saída de um escopo, como por exemplo fechar um socket ou um arquivo. A vantagem é que em muitos casos para se implementar um RAII é necessário se criar uma classe para se adicionar o código de liberação do recurso no destrutor, com o ScopeExit isto pode ser feito diretamente em funções ou métodos onde o recurso é utilizado.
  • Swap: uma versão melhorada da std::swap, que além de suportar os operadores de atribuição e construtor de cópia, faz uso de um método swap ou uma função swap (que tem que ser definida para os tipos envolvidos).

Caso tenha dificuldades em compilar esta novar versão, experimente ler o artigo: Compilando a Boost.