quinta-feira, 29 de novembro de 2007

Artigo: Reinstall Windows and outfit your system with all freeware programs

Artigo do FreewareGenius bem interessante pra quem quer conhecer uma grande variedade de software de ótima qualidade e custo zero.

Acesse o artigo aqui e também leia os comentários, que por sinal tem links pra outros freewares interessantes.

sexta-feira, 23 de novembro de 2007

Dica C++: Minimizando a dependência de arquivos - Parte 1

Algumas vezes nos deparamos com situações em que as declarações que construímos precisam fazer referência umas às outras, de forma a implementar um relacionamento entre ambas as partes. Quando esse relacionamento é modelado, geralmente desejamos colocar cada parte declarada num arquivo diferente, de forma que fiquem logicamente e fisicamente separados.

Se por exemplo criamos duas classes, A e B, criamos dois arquivos de declaração respectivos, A.h e B.h. Só que nossa classe A precisa usar um objeto da classe B, que por sua vez também precisa usar um objeto da classe A. Nesse caso, se A.h incluir B.h e B.h incluir A.h, claramente está sendo criado uma dependência circular, o que não é permitido (A.h irá incluir a declaração de B.h, que irá incluir a declaração de A.h, que írá incluir...).

Na maioria dos casos, os programadores são levados a declarar as classes num mesmo arquivo, digamos AB.h. Veja o exemplo abaixo:

Por questões de simplificação, as classes foram criadas ignorando uso de constantes, operadores, construtores, destrutores, etc.

Arquivo AB.h_______________________________________________

#ifndef AB_H
#define AB_H
        class B; // pre-declaracao
        class A
{
public:
B* GetB();
void SetB(B *b);
private:
B *_b;
};
        class B
{
public:
A* GetA();
void SetA(A *a);
private:
A *_a;
};
#endif

Arquivo AB.cpp_____________________________________________

#include "AB.h"
// class A
B* A::GetB()
{
return ( _b );
}
void A::SetB(B *b)
{
_b = b;
}
// class B
A* B::GetA()
{
return ( _a );
}
void B::SetA(A *a)
{
_a = a;
}

__________________________________________________________


Isso termina com o problema da dependência circular, mas também traz alguns efeitos indesejados:



  • No arquivo de declaração é perdida a abstração de A separado de B e vice-versa;
  • Não há como reutilizar A sem B, e vice-versa (o principal);

Todavia, há outras formas de resolver ou minimizar o problema e conseqüentemente seus efeitos.


Solução 1: Limitar à dependência da declaração antecipada


Se A não tem conhecimento dos detalhes (métodos, atributos e subtipos) de B e vice-versa, eles só precisam saber que deve haver a respectiva declaração de quem eles precisam em algum lugar. Onde ? Não importa. Só precisam saber que existe. É aí que está a solução.


Isto quer dizer que A não precisa conhecer a declaração de B especificamente, mas apenas saber que B existe.


Arquivo A.h________________________________________________

#ifndef A_H
#define
A_H
        class B; // pre-declaracao
        class A
{
public:
B* GetB();
void SetB(B *b);
private:
B *_b;
}; 
#endif
__________________________________________________
(O arquivo A.cpp conterá a implentação de A mostrada no arquivo AB.cpp) 
 

Arquivo B.h________________________________________________

#ifndef B_H
#define B_H
        class A; // pre-declaracao
        class B
{
public:
A* GetA();
void SetA(A *a);
private:
A *_a;
}; 
#endif
__________________________________________________

(O arquivo B.cpp conterá a implentação de B mostrada no arquivo AB.cpp)


Em nenhum dos arquivos (de cabeçalho ou de implementação) é necessário especificar a declaração do tipo pré-declarado usado.


Assim, A e B tem um conhecimento praticamente abstrato um do outro. Cada um sabe que o outro existe, mas não sabe como ele é.


Com isso é aberta a possibilidade de reutilização de um mesmo arquivo em outros projetos, já que qualquer uma das partes pode variar que a outra continua não tendo conhecimento.


Vale lembrar que esta solução é válida pois as partes não se conhecem realmente (só se conhecem de nome). Quando precisarem se conhecer serão adotadas outras soluções, as quais veremos nas próximas partes deste modesto artigo. ;)

quinta-feira, 8 de novembro de 2007

Dica C++: Usando auto_ptr

A auto_ptr é uma classe parte da STL que permite guardar a referência para um objeto de qualquer tipo. Quando se cria um objeto da classe auto_ptr, passando para ela o objeto apontado, ele terá a posse do objeto apontado.

Por exemplo:

class ClasseQualquer
{
public:
int valor;
};

auto_ptr< ClasseQualquer > meuAutoPtr(
  new ClasseQualquer );


O objeto criado pela instrução new ClasseQualquer será agora o objeto apontado por meuAutoPtr.


Quando a instância de meuAutoPtr for destruída, ela destrói o objeto que ela aponta. Assim, quando o escopo da variável meuAutoPtr terminar, ela automaticamente irá liberar da memória o (dar um delete no) objeto para o qual ela aponta.


A classe auto_ptr possui o método get para retornar o objeto apontado:


meuAutoPtr.get(); // irá retornar a instância de ClasseQualquer


Logo, para alterar o atributo valor:


meuAutoPtr.get()->valor = 100;


Só que auto_ptr também sobrecarrega o operador ->, fazendo com que ele também retorne o objeto apontado (sendo X uma classe qualquer a assinatura do método seria "X* operator ->() const;". Devo falar mais sobre sobrecarga de operadores em postagens futuras.). Logo, podemos usar


meuAutoPtr->valor = 100;


como se meuAutoPtr fosse o próprio objeto de ClasseQualquer.


auto_ptr possui o método release, para liberar a memória do objeto apontado por ela:


meuAutoPtr.release(); // destroi a instância de ClasseQualquer


E o método reset, para fazer com que ela aponte para outro objeto. O método reset irá destruir o objeto apontado antes de receber o novo:


meuAutoPtr.reset( new ClasseQualquer );


Na grande maioria das vezes, não precisamos usar os métodos oferecidos por auto_ptr pois sua utilidade maior é mesmo a de poder guardar a referência para um objeto e destruí-lo automaticamente assim que seu escopo terminar.

void FuncaoExemplo()
{
// Um objeto de ClasseQualquer é
// instanciado

auto_ptr< ClasseQualquer > meuAutoPtr(
new ClasseQualquer );
 
// Podemos acessar o objeto criado atraves
// do objeto auto_ptr de forma praticamente
// transparente (devido ao operator ->)

meuAutoPtr->valor = 100;
 
cout << "O valor é: " << meuAutoPtr->valor;
 
// O MAIS IMPORTANTE:
// Nao e' preciso desalocar a memoria que
// foi criada e passada para o auto_ptr.
// Como o escopo da variavel meuAutoPtr
// terminou ela deleta o objeto apontado

}

Essa é uma maneira simples de criar objetos com new, sem que seja preciso usar delete (ou seja, sem que seja preciso se preocupar com a memória alocada).


Cuidados no uso de auto_ptr

Quando criamos um objeto da classe auto_ptr, ele geralmente não deve ser um ponteiro. Isso porque, sendo ponteiro, nos obrigaria a usar new e delete, o que faria perder o sentido da classe.
void FuncaoExemplo2_UsoSemSentido()
{
auto_ptr< ClasseQualquer > *meuAutoPtr =
new auto_ptr< ClasseQualquer >(
new ClasseQualquer );
 
( *meuAutoPtr )->valor = 100;
 
cout << "O valor é: " <<
( *meuAutoPtr )->valor;
 
delete meuAutoPtr;
}

Veja que foi preciso acessar o valor do ponteiro meuAutoPtr, usando asterisco...

( *meuAutoPtr )->valor = 100;

...para não precisar acessar usando get:

meuAutoPtr->get()->valor = 100;

Outro cuidado importante que deve-se ter é o atribuir uma variável da classe auto_ptr a outra. A atribuição passa a posse do objeto para a variável receptora (do lado esquerdo). Isto porque auto_ptr admite somente um dono para um objeto:

// Cria umDono possuindo uma instancia de
// ClasseQualquer

auto_ptr< ClasseQualquer > umDono(
new ClasseQualquer );
 
// Faz com que novoDono seja o novo dono da
// instancia e com que umDono não seja mais
// dono de nada !!!

auto_ptr< ClasseQualquer > novoDono = umDono;
 
umDono->valor = 100; // ERRO !
 
novoDono->valor = 100; // OK

Conclusão


Podemos usar a classe auto_ptr para nos ajudar a criar instâncias de outras classes sem que precisemos nos preocupar em gerenciar a memória alocada.


Em tempo, a classe pertence à biblioteca memory e é declarada dentro do namespace std.

quarta-feira, 31 de outubro de 2007

Utilitário: VLC Media Player

O VLC Media Player é basicamente um tocador de vídeo e música opensource e multi-plataforma com suporte a diversos formatos sem a necessidade de instalação de codecs. Possui skins, suporta dezenas de formatos de áudio e vídeo, e pode ser usado como servidor de streaming,fazendo vídeo on demand com facilidade.

Vale a pena conferir. ;)

terça-feira, 23 de outubro de 2007

Apple MacOS X Leopard

A nova versão do sistema operacional da Apple, MacOS 10.5 (também chamada de Leopard), traz mais de 300 novidades. O interessante é que esta versão traz mais novidades que muitos sistemas operacionais ditos "novos" por aí... ;)

Em especial, destaco algumas novidades de segurança:
  • Marcação (tagging) de programas: Antes do programa ser executado pela primeira vez, é exibido algumas informações sobre sua procedência, como o site do qual foi baixado, qual programa usado para o download, etc.
  • Controle de assinatura digital de programas: Permite controlar assinaturas digitais que atestam que os programas são realmente de seus fabricantes.
  • Firewall de programas: Gerencia tentativas de conexão de/para programas, possibilitando permitir ou bloquear as requisições.
  • Virtualização (sandboxing) de programas: Restringe o acesso de aplicações a diversos recursos do sistema operacional (como acesso a arquivos, rede, etc.) permitindo um maior nível de controle sobre o comportamento de programas e conseqüentemente sobre vírus e cavalos de tróia.
  • Realocação de endereços de memória: Realoca os endereços de memória de bibliotecas de funções de forma a frustrar ataques de hackers/crackers que fazem uso do desvio da execução de programas para endereços de memória pré-determinados onde estão as funções de sistema.
Faça um tour pela nova versão, que está prevista para ser liberada dia 26 deste mês.

terça-feira, 16 de outubro de 2007

Novidades da HTML 5

A Hyper Text Markup Language está ganhando um upgrade, refletindo a realidade atual da Internet e facilitando o desenvolvimento de conteúdo. Tags especiais para artigos (article), navegação (nav) e mídia (video, audio, etc.) são exemplos de facilidades que estarão presentes na nova versão.

Confira algumas tags:

SECTION - Parte, sessão ou capítulo de um livro ou cabeçalho.
HEADER - Cabeçalho da página (não confundir com HEAD).
FOOTER - Rodapé da página
NAV - Coleção de links para outras páginas
ARTICLE - Um artigo externo, como de uma revista, blog, etc.
ASIDE - Serve para agrupar um determinado conteúdo para, por exemplo colocá-lo numa barra lateral na página.
FIGURE - Organiza melhor as informações relacionadas à uma figura, vídeo, áudio, etc.
DIALOG - Permite organizar um diálogo entre pessoas, de forma a formatar diferentemente dependendo de cada locutor.

Veja exemplos no artigo New elementos in HTML.

Algumas perguntas surgem, quase que sem resposta:

Quando os browsers começarão a dar suporte à ela ?

Quando será o momento em que poderemos utilizá-la, sem temer que os usuários não a tenham em seus browsers ?

Resta esperar, torcendo para que não demore.

Mais informações em HTML 5 - Working Draft

sábado, 13 de outubro de 2007

Star Wars - The Force Unleashed

Além da saga no cinema e das temporadas em desenho na TV, nos games Star Wars continua dando bons frutos. Dessa vez, com The Force Unleashed, promete impressionar.

Dirigido pelo próprio George Lucas, o jogo se passa entre os episódios III (A vingança do Sith) e IV (Uma nova esperança). Nele os jogadores irão auxiliar o vilão Darth Vader, em sua busca para dominar o universo Jedi, e tomar decisões que poderão mudar o curso de seu destino (inclusive o final do jogo ;) ). Ao jogar você toma forma de um aprendiz secreto de Vader, que foi treinado por muitos anos na arte Sith. No entanto, cresce forte o lado da Força em você e Vader o dá missões secretas para eliminar os rivais do Lord da Escuridão. Vader espera que seu aprendiz irá um dia trilhar o destino da escuridão, ficando ao seu lado no confronto contra o Império. Mas isso só o destino, através de suas ações, irá dizer...

Apesar da história ser interessante, não é tanto por ela que, em minha opinião, o jogo irá arregalar os olhos do jogador. O que irá de fato chamar a atenção é a perspectiva com a qual foi feito o jogo. As possibilidades do jogo foram repensadas para refletir as novas tecnologias desenvolvidas, dando uma nova escala e escopo para a Força.

Andei dando uma olhada no novo game engine dele e tanto a física como a inteligência artificial estão muito melhores em relação aos jogos atuais, não só em relação a outros Star Wars. Isto porque foram reunidas duas novas tecnologias, que passaram a ser incorporadas ao Havok Physics System:

Digital Molecular Matter (DMM), da Pixelux Entertainment, faz os objetos serem deformados ou quebrados de forma quase idêntica aos objetos reais. A cada material foram dadas propriedades físicas diferentes, que reagem de forma diferente dependendo da força, peso e posição com que objetos interagem. Não há mais aquele frame de animação igual para quebrar paredes de um mesmo tipo, por exemplo, com os quais estamos acostumados (há exceções, claro em alguns poucos jogos).

Sem DMM:                                      Com DMM:Euphoria, da NaturalMotion Ltd., faz os personagens responderem de forma diferente de acordo com a situação em que se encontra, através de um simulador. Não há mais scripts pré-determinados para reação dos personagens. A cada interação eles podem reagir de forma diferente, dando ao jogo um nível muito melhor de realismo.

Com essas duas tecnologias, a experiência de jogo muda totalmente, a cada partida. A interação com personagens e cenários muda a cada vez, trazendo novas possibilidades e maior diversão.

E tudo isso, aliado ao ambiente excêntrico de Star Wars, aumenta a promessa de que The Force Unleashed será um grande sucesso.  

Previsto para início de 2008. Confira mais informações no site oficial e vídeos no YouTube.

terça-feira, 28 de agosto de 2007

Mudanças do C++0x

Veja algumas mudanças que estarão na nova versão do C++ na definição do Wikipedia e no artigo no CodeGuru.

É duro ter de esperar até meados de 2009...

segunda-feira, 13 de agosto de 2007

Entrevista com "seu" Bjarne - C++0x

Entrevista com Bjarne Stroustrup, criador da linguagem C++, a respeito padrão ISO do C++ que está por vir.

Veja aqui. A entrevista possui versões para download (vídeo) em diversos formatos.

Só lembrando, o 0x ( do "C++0x") significa o possível ano da publicação do novo padrão. Espera-se que seja em 2009. O padrão atual é o ISO C++ 1998 (ou C++98).

quarta-feira, 8 de agosto de 2007

Novidades em displays flexíveis

A joint venture LG Philips LCD, que fabrica displays flexíveis de diodo orgânico emissor de luz (os chamados OLEDs, em inglês) sob substrato de plástico flexível, impressionou ao lançar o primeiro papel eletrônico flexível colorido tamanho A4. Com 14,1 polegadas e 0,3 milímetros de espessura, o papel pode exibir até 4096 cores.

Claro que não alcança a resolução dos monitores LCD atuais, mas para o que se destina é uma marca bem razoável. Isso porque a melhor tecnologia anterior de papel eletrônico, cujo lançamento foi feito pela mesma empresa em outubro de 2005, era uma tela monocromática de 10,1 polegadas.

A mesma LG Philips LCD também está desenvolvendo um display de água e óleo, que possui um custo de produção bem menor que os OLEDs atuais. A formação de imagens se dá com um novo jeito de iluminar os pixels no display flexível: Simplificando, montam-se células minúsculas, cada uma com uma camada de óleo sobre uma camada de água, sobre uma superfície com as três cores básicas (vermelho, verde e azul). O óleo serve para obscurecer a superfície com as cores. Quando é aplicado eletricidade, o óleo se move sob a água. Ao se mover, a superfície colorida é revelada, podendo mudar sua cor dependendo da posição e da intensidade do óleo sobre as cores, que é controlada pela eletricidade. O resultado são cores vivas e brilhantes, como a capa de uma revista.

Veja mais detalhes sobre este display de água e óleo na página de sua patente.

terça-feira, 7 de agosto de 2007

Impressoras Laser podem fazer mal à saúde

Não, não é uma piada. Pesquisadores da Universidade de Tecnologia de Queensland, na Austrália, descobriram que certas impressoras laser liberam partículas de material similar ao do toner e que podem ser inaladas por serem extremamente finas.

Alguns números do estudo, que avaliou 62 impressoras de marcas comuns como Canon, HP, Ricoh e Toshiba:

17 foram qualificadas como "grandes emissoras de partículas", com níveis de emissão equivalentes à fumaça de um cigarro;
6 liberavam níveis médios de partículas;
2 liberavam baixos níveis; e
37 não liberavam partículas que prejudicassem a qualidade do ar;

No estudo, a Dra. Lidia Morawska adverte que estas partículas podem trazer um sério risco à saúde.

Será que daqui a um tempo vai acontecer de pessoas processarem empresas de impressoras por problemas respiratórios, dentre outros, como ocorreu com a indústria de cigarro ???

GNU/Linux brasileiro sabor XP

Distribuição criada com intuito de ser usada por usuários que estão acostumados com o Windows XP.

http://www.famelix.com.br/

Screenshots aqui e aqui.

quarta-feira, 1 de agosto de 2007

Análise de SOs

Análise feita por John Halanka, do site CIO.com, onde é feita uma comparação dos prós e contras do uso de Windows, Linux e MacOS em empresas, sobre a visão de um Chief Information Officer.

Veja em Windows vs. Linux vs. OSX.

sábado, 14 de julho de 2007

Código de Ética da Engenharia de Software

Vale à pena conhecer e, principalmente, seguir.

http://oeccombo.cwru.edu/codes/softeng.html

Veja também a versão em PDF.

Mais informações em Adopting the Software Engineering Code of Ethics and Professional Practive.

sexta-feira, 8 de junho de 2007

Um novo conceito em visualização de imagens

Essa é a nova proposta do Photosynth, um projeto originado na Seadragon Software, recém adquirida pela Microsoft.

Com ele você pode ver fotos por qualquer ângulo, dar zoom em imagens com a mesma velocidade, independente do tamanho, agrupar fotos inter-relacionadas e muito mais.

Eu assisti ao vídeo, instalei o plug-in no meu Firefox e experimentei um pouco o Photosynth. Bem interessante por sinal.

Sinto que hoje há uma forte tendência em criar interfaces gráficas em três dimensões (3D), de forma que possamos manipular objetos de formas cada vez mais próximas às do mundo real.

Aliás, essa é a proposta ideal das interfaces com o usuário. Ser intuitiva ao ponto de não ser preciso criar muitas metáforas e abstrações para operar o computador. Manipular janelas e clicar em botões quadrados e menus deslizantes está cada vez mais "fora de moda". Sabemos, com certeza, que essa não é a maneira ideal - apesar de termos nos acostumado ao longo do tempo - de interagir com  o PC. Mas se será como em Minority Report ou em Matrix, só um futuro, cada vez mais próximo, irá dizer.

quinta-feira, 7 de junho de 2007

Utilitário: Unlocker

Quem não já tentou excluir um arquivo e o arquivo não pôde ser excluído porque "estava sendo utilizado" ? Você fechou o programa que estava usando o arquivo, mas ele continua lá, bloqueado, sem que você possa mandá-lo pros confins da lixeira ou mesmo eliminá-lo diretamente (Shift+Del).

Pra resolver problemas deste tipo que existe o Unlocker, um freeware que se integra ao menu de contexto, permitindo que você destrave o arquivo, ou pasta, e possa fazer com ele o que bem desejar.

Screenshot do Unlocker

Dica C++: Passagem correta de objetos em funções e métodos

Existem diferentes formas de se lidar com alocação de objetos e sua passagem para métodos e funções. A escolha pela maneira correta pode evitar ter que lidar com diversos problemas e, consequentemente, com bugs e dificuldades de depuração.

Vamos analisar alguns casos e ver como é possível ter implementações diferentes para um mesmo tipo de necessidade, e como determinado tipo de implementação pode interferir no resultado final, em aspectos de confiabilidade, segurança e performance.

Funções que recebem objetos por valor

Suponha que haja necessidade da criação de uma função qualquer que tome um objeto como parâmetro à fim de obter alguns de seus valores. Chamarei esta função de FuncaoXYZ:

void FuncaoXYZ(...);

Para a passagem de um objeto de uma classe qualquer (que chamarei de TClasseQualquer) por valor, temos algumas possibilidades para esta simples função:

(1) void FuncaoXYZ(TClasseQualquer objeto);

(2) void FuncaoXYZ(const TClasseQualquer objeto);

(3) void FuncaoXYZ(const TClasseQualquer *objeto);

(4) void FuncaoXYZ(const TClasseQualquer &objeto);

Neste caso, vemos como é importante o conhecimento da linguagem de programação na qual se está implementando. Este conhecimento influencia diretamente na escolha de implementação ótima e outra passível de problemas.

Nas funções acima, tanto (1) como (2) fazem uma cópia do objeto e trabalham com esta cópia dentro da função. Ou seja, a cada vez que a função é chamada ela precisa criar uma nova cópia do objeto. Isso pode consumir tempo e recursos, se o objeto for "grande" e esta operação for executada repetidas vezes, como dentro de um laço de repetição, por exemplo.

Em (1) também não há garantia de que a função não fará modificações no objeto, pois o mesmo não foi passado como uma constante. Mesmo que neste tipo de implementação ela esteja criando uma cópia do objeto original e por isso não irá modificá-lo, esse é um tipo de comportamento indesejado, que deveria ser evitado.

Em (3) não há certeza de que o objeto passado não é nulo (NULL). Logo, a função sempre deverá fazer o teste antes de acessar o objeto recebido, sob pena de acessar um endereço de memória inválido. Esse tipo de situação deve ser evitado, sendo portanto desaconselhável a passagem de objetos por ponteiro quando só desejamos acessar seus valores, sem alterá-lo.

Assim, em (4), chegamos a uma implementação que nos livra de ter que checar se o objeto recebido é nulo, por não ser um ponteiro, que garante que ele não poderá ser modificado dentro da função, por ser uma constante, e que não criará uma cópia do objeto recebido, já que foi criado um apelido (uma referência, ou seja &) para o objeto original.

Logo, utilizando a notação "const T&" (onde T é um tipo qualquer) para funções que recebem um objeto por valor, garantimos um determinado comportamento e assim saberemos, se algo der errado, que diversos tipos de condições (como as descritas acima) não irão ocorrer.

Se tomarmos esse tipo de implementação como regra, livramos o software desses problemas.

Métodos que recebem de objetos por valor

Como métodos são funções dentro de classes, podemos levar em consideração a mesma regra adotada para funções vista acima (notação "const T&").

Porém, há ainda um aspecto importante que devemos analisar: O que garante que o método, em sua implementação, não irá modificar os atributos da classe, caso desejado ?

Em C++ você dá esta garantia adicionando "const" após a declaração do método:

void FuncaoXYZ(
  const TClasseQualquer &objeto) const;

Assim, o compilador emite um erro se método tentar alterar qualquer atributo da classe.

Funções que recebem objetos por referência

Quando há a necessidade de alterar um objeto recebido por parâmetro, dentro de uma função, podemos fazê-lo declarando de uma das seguintes formas:

(1) void FuncaoXYZ(TClasseQualquer *objeto);

(2) void FuncaoXYZ(TClasseQualquer &objeto);

Como foi visto, fica claro a escolha de (2) pois não temos que testar se o objeto recebido é nulo. E também fica mais difícil de pensar em deletar o objeto da memória, já que não é um ponteiro.

Métodos que recebem objetos por referência

A mesma notação para funções pode ser aplicada, podendo ser adicionado o uso de const quando aplicável (quando não se desejar mudar o valor de algum atributo da classe dentro da implementação do método).

Outros usos

Como a notação de referência é útil para nos poupar dos aborrecimentos trazidos pelos ponteiros, podemos utilizá-la sempre que possível. Mesmo utilizando bibliotecas de terceiros que possuam a notação de ponteiro (*), podemos adaptar seu uso.

Por exemplo:

void TMinhaClasse::ReimplementacaoDoMetodoASDFG(
  const TAlgumaClasse *ponteiro)
{
    #ifdef _DEBUG // PRE-CONDICAO
    assert( ponteiro != NULL );  
    #endif

    const TAlgumaClasse &referencia = ponteiro;

    // trabalha com "referencia" ao inves
    // de "ponteiro"
    // ...

}

Ao invés de utilizar o ponteiro real, criamos uma referência para ele.

Vale lembrar que se a função aceitasse nulo (NULL) como um valor válido, não deveríamos substituir o ponteiro pela notação de referência. (Ou até poderíamos fazê-lo se o valor nulo pudesse ser tratado em um bloco de código separado (com um if, por exemplo), sendo um caso a parte, e o resto da função utilizasse o objeto como sendo não-nulo.)

Conclusão

A utilização correta dos recursos da linguagem pode trazer diversos benefícios ao software escrito, desde melhoria de performance até diminuição dos índices de erro e tempo de depuração.

No caso do uso de objetos em funções e métodos, evita problemas indesejáveis relacionados à alocação memória e acesso irrestrito à informações.

Sempre que aplicável, devemos utilizar parâmetros constantes e referências ao invés de ponteiros.

sexta-feira, 25 de maio de 2007

Windows: Compartilhamentos ocultos

Para você que é usuário de Windows XP, 2000 ou Vista, um aviso: seu computador tem uma back door por padrão. Por padrão pois, como sabemos, na família Windows os itens de segurança são quase todos desativados "de fábrica" pois primam pela "facilidade de uso". Por que, ao invés, não deixam os itens de segurança todos habilitados e criam um gerenciador de itens de segurança simples de usar ? Vai saber...
A back door ao qual me refiro, na verdade é referenciada como uma funcionalidade presente no Windows. Por padrão, os drives do micro são compartilhados e isso fica oculto ao usuário, por meio do uso do sufixo $ ao compartilhamento. Por exemplo, a unidade C é compartilhada como C$, fazendo ela ficar oculta. Mas na verdade ela pode ser acessada via rede, por um usuário que possua Login e Senha apropriados. Neste ponto você deve estar pensando: bem eu uso uma boa senha, e esta somente eu conheço, certo ? Pode ser. Mas você sabe ou lembra se você ou quem instalou o Windows em seu computador lembrou de colocar senha para o usuário Administrador, que possui acesso total ?
Pelo sim ou pelo não, é melhor garantir...

Para mudar a senha do usuário Administrador:

1. WinKey+R (ou Iniciar -> Executar)
2. Digite control userpasswords2
3. Selecione o usuário Administrador e clique em Redefinir senha
4. Digite a senha e a confirmação.


Para visualizar todos os compartilhamentos:


1. WinKey+R (ou Iniciar -> Executar)
2. Digite compmgmt.msc
3. Agora, na janela Gerenciamento do computador, expanda o nó Pastas compartilhadas e clique em Compartilhamentos

Mesmo se você clicar sobre a unidade que quer remover o compartilhamento (por exemplo C$) com o botão direito do mouse e escolher Interromper compartilhamento, o Windows irá recompartilhá-la quando você reiniciar o computador.


Para desabilitar os compartilhamentos indesejados:

0. (Sim, passo zero, ou o passo antes de você realmente começar a fazer) Faça uma cópia do registro do Windows por segurança, criando um Ponto de Restauração do sistema: Tecle
WinKey+R (ou acesse Iniciar->Executar) e digite %SystemRoot%\System32\restore\rstrui.exe
( ou então vá em Iniciar->Programas->Acessórios->Ferramentas de sistema->Restauração do sistema) e crie um ponto de restauração.

1.
WinKey+R (ou Iniciar -> Executar)
2. Digite regedit
3. Agora, no Editor de Registro, navegue até HKEY_LOCAL_MACHINE\SYSTEM\
CurrentControlSet\Services\lanmanserver\parameters
4. Crie um novo valor DWORD chamado AutoShareServer com valor 0 (zero).
5. Crie um novo valor DWORD chamado AutoShareWks com valor 0 (zero).
6. Reinicie o computador para que as alterações surtam efeito.


Pronto, agora os compartilhamentos ocultos não poderão ser mais acessados.

quinta-feira, 24 de maio de 2007

Site: OSAlt

O OSAlt lista softwares opensource como alternativas à softwares pagos conhecidos. Para um determinado software pago, ele apresenta uma lista de softwares gratuitos alternativos.

Vale à pena conhecer: http://www.osalt.com/

sexta-feira, 18 de maio de 2007

S.O.: Wubi

O Wubi é um distribuição de Linux baseada no Ubuntu com desktop 3D, instalação sem fazer partição no HD, sem ter que criar disco de boot, sem mexer nos dados existentes e com instalador e desinstalador que executa de dentro do Windows.

Não há mais desculpa para não experimentar o Linux.... ;)

Ps: Não deixe de ver os screenshots.

quarta-feira, 9 de maio de 2007

Microsoft lança novas ferramentas para web

No último post, citei a tecnologia Flex e a ferramenta Apollo, ambas da Adobe. Agora, a Microsoft também na briga com o lançamento do Silverlight e do Expression Studio e com suporte ao Silverlight no Visual Studio.

O Silverlight, assim como o Flex, é um framework para criação de aplicações web com recursos multimídia. Ambos dão diversas facilidades de criação e gerenciamento de conteúdo e são cross-plataform (no caso da ferramenta da Microsoft, há suporte ao MacOS X). O Silverlight é baseado no framework .NET, o que é vantajoso para quem desenvolve sob a plataforma Windows, por causa de sua integração. Assim como no Flex, é possível usar as linguagens e ferramentas tradicionais de desenvolvimento web (XHTML, XML, CSS, etc.) para criação e integração de conteúdo.

O Silverlight SDK também pode ser baixado gratuitamente.

Será realmente interessante ver os frameworks disputando lugar no mercado de desenvolvimento web.

quarta-feira, 2 de maio de 2007

Adobe entrando para ganhar

A empresa dona de softwares como Photoshop, Dreamweaver, Acrobat e ColdFusion está entrando pesado no mercado de desenvolvimento. Depois de comprar a Macromedia, dona da tecnologia Flash e de diversas ferramentas, lançou o Flex 2, planeja lançar o Apollo, e liberar o Flex SDK sobre a Mozilla Public License (MPL). Isso pode mudar os ventos do desenvolvimento web e, pouco a pouco, do desenvolvimento para desktop.

A Adobe teve uma grande sacada em abrir o Flex (um conjunto de tecnologias e ferramentas para acelerar a construção e distribuição de aplicativos web visualmente ricos e de alta performance) sobre a licença MPL, pois isto possibilitará uma adoção pelo mercado muito mais rápida.

E ainda com o Apollo (que permite usar tecnologias como Flash, Flex e Ajax para desenvolvimento de aplicações para desktop), diversas empresas podem abandonar o desenvolvimento de aplicações pelas ferramentas e linguagens tradicionais de desktop (como MS Visual Studio, Borland Developers Studio, Eclipse, etc). Isto porque o Apollo permite a criação de aplicações cross-plataform (ou seja, que rodam em Windows, Linux, Mac, Solaris, etc.), que usam todo o poder de interface com usuário do Flash, com todo o poder de conectividade e interoperabilidade das linguagens web existentes (JavaScript, HTML, etc.), podendo rodar fora do browser e sem conexão com a internet (offline). E como é comum nos softwares da Adobe, todo o desenvolvimento se dá de forma rápida e fácil.

Grandes empresas já estão apostando no Flex e no Apollo, inclusive lançando novos produtos e serviços que os utilizam. Como exemplo, há o eBay, que está construindo uma aplicação com Apollo para atrair mais clientes.

Se o desenvolvimento web atualmente está rumo ao Flash e ao Ajax, com essas novas ferramentas, o desenvolvimento para desktop pode seguramente caminhar para esse lado.

quarta-feira, 25 de abril de 2007

Hora de acordar

Ligado em rede ao meu micro, há um computador com arquivos que volta e meia preciso acessar. Quando este computador está ligado, acesso a pasta compartilhada e voilá. Quando o micro está desligado, busco a chave, desço três lançes de escada, abro uma porta, ligo as luzes, o micro, espero o boot, faço logon, abro a pasta com o arquivo e envio pela rede. Depois desligo o micro, apago as luzes, tranco a porta, subo a escada, guardo a chave e volto pro meu micro para abrir o arquivo enviado. Se optei por desligar tudo e depois descubro que tenho que pegar outro arquivo, tenho que fazer tudo outra vez...

Bom... tinha.

A placa mãe do micro que acesso tem suporte a WOL (Wake On LAN), que aceita com que o micro seja ligado a partir de outra máquina na rede. A coisa funciona assim: A placa mãe deixa a placa de rede em standby. Quando a placa de rede recebe um "pacote mágico" - a saber, é um pacote que tem em seu campo de dados o endereço MAC da placa de rede repetido 16 vezes - ela envia um sinal de ligar para a placa mãe e esta então inicia o computador normalmente.

Para saber se uma placa mãe tem suporte a WOL, ou você vê pelo BIOS, ou pelo manual, ou no site do fabricante. No meu caso, foi mesmo pelo BIOS. Vá em Power Management ou qualquer outra opção de energia disponível e veja se há algumas destas siglas:

- WOL (Wake On LAN)

- ACPI (Advanced Configuration and Power Interface)

No meu caso, havia uma opção para habilitação de suporte a ACPI (algo como "ACPI aware OS (Yes/No)". Isso permite que o sistema operacional faça o controle de energia, podendo selecionar os dispositivos que serão desligados ou não).

Com o ACPI, há diferentes níveis de energia suportados:

S0 - Tudo ligado

S1 - Baixo consumo (também conhecido como sleep mode): o clock da CPU é interrompido mas a RAM continua ligada e sendo atualizada.

S2 - Similar à S1, mas com a CPU desligada.

S3 - Suspenso para RAM (também conhecido como standby mode): basicamente todos os componentes são desligados, exceto a RAM.

S4 - Suspenso para disco (também conhecido como hibernate mode):  o conteúdo da memória é gravado no HD e a RAM é recarregada quando o sistema é acordado.

S5 - Tudo desligado

 

No meu caso haviam S1 e S3. Configurei para S3.

Depois procure em outra sessão do BIOS pela habilitação da ligação do micro via LAN (se não me engano no meu caso foi em Advanced Settings -> LAN Wake-up).

Estando o BIOS configurado, resta configurar o sistema operacional. No caso de Linux, algumas distribuições novas suportam ACPI/WOL, como a RedHat, Fedora, SUSE, Mandriva, etc. No caso da família Windows, é preciso a versão 98 ou superior (Me, 2000, XP).

Acesse as Conexões de Rede disponíveis, vá na conexão que está sendo usada para LAN, abra suas Propriedades, acesse a configuração da placa de rede utilizada, vá em Gerenciamento de Energia (no caso do XP por exemplo) e marque "Este dispositivo pode ativar novamente o computador". Por questões de segurança, também marque "Só estações de gerenciamento podem ativar o computador". Pronto, o micro que será ligado está todo configurado.

Agora, no micro que enviará a mensagem para ligar, basta fazer o download de um programa que envie o "pacote mágico" pela rede. No meu caso, usei o freeware WOL, da Simple-Ware. Com ele, estando os dois micros ligados, basta fornecer o IP do micro a ser ligado e clicar em "MAC" para ele capturar o MAC da placa de rede do micro a ser ligado. Clicando em OK ele já enviará o pacote mágico pro micro destino.

Tudo pronto. Desligue o micro que você irá ligar pela rede, vá no micro que tem o programa WOL e clique em OK. Se tudo foi configurado corretamente, o outro micro irá ligar como mágica ;).

Para complementar, no meu caso, instalei o opensource UltraVNC para controlar o outro micro à distância.

Assim, agora sem sair da minha cadeira, ligo o outro micro, faço logon, transfiro até arquivos fora da pasta compartilhada e desligo o micro. Tudo com o mouse.

Ê preguiça... :)

quarta-feira, 14 de março de 2007

Utilitário: TaskSwitchXP

Freeware que substitui o convencional alternador de tarefas (Alt+Tab)do Windows XP por uma versão com mais recursos.

O TaskSwitchXP faz miniaturas da imagem da janela aberta e possibilita clicar em uma tarefa com o botão direito e acessar opções extras. Também pode ser totalmente personalizado, bastando acessar o menu "Preferências" (sim, existe versão para Português do Brasil).

 

 

 

 

 

 

 

 

 

Veja aqui.

terça-feira, 27 de fevereiro de 2007

Você crê em tudo o que vê ?

Você pode dizer qual o degrau mais baixo nesta imagem ?













Continua, continua e nunca termina... :)

Essas e outras ilusões de ótica bem interessantes podem ser conferidas em EyeTricks.
Lá, além das diversas ilusões, há um Gerador Holográfico 3D à venda - mas somente para os EUA. :(

USBs quebrando um galho









Chaveiros e outros dispositivos USB estão virando gadgets cada vez mais bizarros... :)
Veja alguns em Dynamism e Fosfor Gadgets.

sábado, 24 de fevereiro de 2007

Impressão sem tinta

A Xerox está desenvolvendo uma impressora que é capaz de imprimir sem usar tinta. O papel da impressão é reutilizável, podendo ser apagado e reimpresso dezenas de vezes.

Sim, isso pode revolucionar o modo como usamos papel.

Imagine que você acabou de receber um e-mail importante e precisa lê-lo em outro lugar, ou achou um artigo super interessante que desejará ler mais tarde. Você normalmente o imprime, lê e joga o papel fora (ou como eu, guarda o papel e vai colocando numa pilha infindável... ;) ).

Com essa nova tecnologia de impressão, o consumo "desenfreado" de papel pode ser subtamente reduzido. Você simplesmente imprime, lê e depois apaga o papel pra usá-lo outra vez.

O papel especial, por enquanto, permite até 50 reimpressões e o conteúdo impresso apaga entre 16 e 24 horas, quando volta a ficar branco.

Veja mais em TFOT.

Utilitário: Tiny Hexer

 

 

 

 

 

 

 

 

Editor hexadecimal freeware leve e com diversas funcionalidades. Tem editor de disco e de memória, suporte a plug-ins, macros (scripts), unicode, tem atualização automática via web e muito mais.

Confira aqui.

sexta-feira, 23 de fevereiro de 2007

Delphi for PHP ?

A empresa CodeGear, a atual responsável pelo desenvolvimento da nova geração de IDEs da Borland, acaba de lançar duas novas versões do Delphi: a Delphi 2007 for Win32 e a Delphi for PHP. Surpreendentemente nada tem a ver o Delphi for PHP com a linguagem Delphi propriamente dita. Só foi mesmo uma má escolha do nome da ferramenta. (Pessoalmente, acho que "PHP DevStudio" ou algo similar faria mais jus...)
A idéia dela é a de trazer a produtividade da RAD usada pelas outras ferramentas (Delphi, Turbo C++, Turbo Pascal, BDS, etc) para a linguagem PHP.

Quanto a ferramenta em si, essa sim está excelente. A CodeGear trouxe a VCL para o PHP, dando o poder de arrastar e soltar componentes para gerar páginas, conexão com banco de dados e tudo mais. Para desenvolvedores PHP, esta é uma ferramenta de mão cheia.

A CodeGear tem acertado no desenvolvimento das novas IDEs. Estão estáveis e cada vez com melhores recursos. Parece que a Borland fez uma boa jogada passando o desenvolvimento pra ela.

quinta-feira, 22 de fevereiro de 2007

Artigo: As coisas que mais aborrecem no Vista

Uma visão um tanto pragmática sobre os novos recursos do último sistema operacional da Microsoft.

The Most Annoying Things About Windows Vista

(Revista PC World)

sábado, 17 de fevereiro de 2007

Tecnologia para sobrevivência

Ontem à noite, liguei a TV e comecei a passear pelos canais quando vi um japonês falando com tradução em legendas. A imagem cortou para a cena de um chip sendo implantado numa placa e, logo, parei de apertar o "canal +" do controle remoto. Era um alto executivo da Toshiba relatando fatos que ocorreram anos atrás e que foram decisivos para a empresa e para o mundo - principalmente no ramo de eletrônicos. A reportagem, produzida provavelmente no final de 2005, não era sobre a Toshiba ou outra empresa, mas sim sobre a indústria de semicondutores.

Acontece que a japonesa Toshiba revolucionou o mercado há alguns anos atrás com o lançamento de uma SRAM de 1MB, três vezes mais que seus concorrentes. Isso fez com que o domínio do mercado, até então americano, fosse abalado e o Japão despontado como uma das empresas líderes em tecnologia de ponta em equipamentos eletrônicos.

Com o rápido crescimento da Toshiba, diversas empresas buscaram entrar no ramo de semicondutores, sobretudo para a produção de SRAM. Estas empresas, com tecnologia há alguns passos atrás da líder do mercado, começaram a convidar engenheiros envolvidos no projeto da rival para fazer uma visita aos centros de tecnologia - o que "obrigava" os engenheiros a fazer um convite de volta, por questões de educação e ética profissional.

Dentre estas empresas, a sul-coreana Samsung se deu melhor. Convidou o engenheiros da Toshiba à uma visita, ofereceu o triplo do salário, apartamento, carro, empregados, secretária e tudo que um empregado pode receber, e acabou contratando cerca de 70 funcionários da rival.

A Samsung rapidamente cresceu. A Toshiba perdeu a liderança e tempo depois anunciou a interrupção do investimento em semicondutores.

O gerente de projetos da Toshiba, Dr. Fujio Masuoka, que tinha um projeto para uma memória que ele batizou de "Flash" - muito superior à SRAM - acabou indo para uma universidade. A empresa não investia em sua memória Flash pois sua política de lucros era de curto prazo e um investimento deste tipo requeria tempo e recursos.

A Samsung, porém, investiu na Flash e dominou o mercado.

O tempo passou, a Toshiba se reergueu e voltou a brigar.

O ex-gerente de projetos trabalha hoje numa nova memória: a SGT, uma espécie de Flash com armazenamento em 3D. Ele foi convidado por uma empresa da Arábia Saudita e eles irão fazer um investimento milionário nessa tecnologia. Só no novo funcionário foram U$ 82 milhões.

Fim da história, por enquanto.

 

Para o Japão e outros países, uma questão que a nós é quase impensada, para eles é uma obsessão: por esses países não terem recursos naturais, tem que se esforçar em se sobressair inventando soluções e tecnologias que o mundo se interesse e compre.

Acredito que como nós não temos esse problema, não encaramos da mesma forma e por isso também poderemos estar sempre um passo aquém.

Enquanto não mudarmos nossa mentalidade, um investimento público maciço em educação e tecnologia não for feito e estiver essa inconcebível carga de impostos, que engessa o investimento privado, nada poderemos fazer senão comprar - e não fabricar - tecnologia.

Aliás, voltando a falar em memórias Flash, hoje a usamos, compramos, trocamos e elas estão em todo o lugar: celulares, câmeras digitais, mp4 players, etc.

Isso até que, enfim, venha a SGT. Ou mesmo outra (como a MRAM). E, novamente, tenhamos de sucumbir à eficiência e a tecnologia alheia.

Infelizmente nossa "criatividade" não supera nosso atraso tecnológico.

Ciência: Universo com outras dimensões

X (plano horizontal), Y (plano vertical), Z (profundidade), Tempo (sim, a teoria da relatividade geral presente) e........... o que mesmo tem mais ??? ;)

Mais uma teoria interessante e, até agora, sem comprovação:

"Esta é uma das principais candidatas à posição de "teoria do tudo", que os físicos têm procurado como forma para unificar as teorias da Relatividade e Quântica. Só que, até agora, não existe uma forma para se testar experimentalmente essa nova proposta de teoria."

Veja em Inovação Tecnológica.

Site legal: IP-Adress ( com um "d" mesmo )

http://www.ip-adress.com/

Nele é possível você ver a localização do seu IP ou ISP (provedor) num mapa e ainda dar zoom.

terça-feira, 13 de fevereiro de 2007

Utilitário: Launchy

A algum tempo eu havia comentado sobre a linha de software (pago) Enso. Contudo, há uma boa alternativa opensource: o Launchy. Ele tem as mesmas funcionalidades do Enso e apresenta extensões (plug-ins) que lhe conferem talvez o mesmo "poder de fogo" de seu concorrente.

http://launchy.net/

No site há mais skins disponíveis.

Dica C++: Classes sem encrencas

Acompanhe o seguinte código:

 

class Relogio
{
public:
    void Tick() const
    {
        const int UM_SEGUNDO = 1000; // ms
  
        Wait( UM_SEGUNDO );
    }; 
};


class BombaRelogio
{
public:
    BombaRelogio(const int contagemRegressiva)
    {
        _contagemRegressiva = contagemRegressiva;
        _relogio = new Relogio;
    }
 
    ~BombaRelogio()
    {
        delete _relogio;
    }
 
    void Ativar() const
    {
        int contador = _contagemRegressiva;
  
        while ( contador > 0 )
        {
            _relogio->Tick();
   
            contador--;
        }
  
        Boom();
    }
 
    void Boom() const
    { 
        cout << "Boom !" << endl;
    }
 
 
private:
    int _contagemRegressiva;
    Relogio *_relogio;
};

 

A princípio esta classe parece funcionar bem e não haver algum problema:

 

...
{
    BombaRelogio bomba( 10 );

    bomba.Ativar();
}

 

Mas por trás de uma declaração "inocente" como esta se escondem bugs traiçoeiros... ;).

Compiladores C++ foram programados para gerar código por default, quando não deixamos o explícito na classe.

No caso acima, por exemplo, um construtor padrão - sem parâmetros de inicialização - foi automaticamente gerado. Algo como isto:

 

BombaRelogio::BombaRelogio()
{
}

 

Assim, ao criarmos um objeto de BombaRelogio sem passar parâmetros, os atributos não são inicializados, causando erros:

 

...
{
    // Nao instancia _relogio
    // nem inicializa _contagemRegressiva.

    BombaRelogio bomba;

    // Erro de acesso invalido a memoria
    // (tentando acessar _relogio) e loop
    // com duracao arbitraria (por nao se
    // ter conhecimento do valor de
    // _contagemRegressiva.

    bomba.Ativar();

    // Ao destrutor ser executado (no fim
    // deste bloco de codigo) ele ainda
    // tentara' destruir um suposto objeto
    // instanciado em _relogio. Isso causara'
    // mais um erro, ja' que o objeto nao
    // havia sido instanciado.

}

 

Veja quantos erros em tão pouco código...

Uma declaração aparentemente inofensiva causando tantos problemas. Bom, além desses ainda podem haver outros.  O que, por exemplo, se espera de uma atribuição do tipo:

 

BombaRelogio bombaRapida( 5 );
BombaRelogio bombaLenta( 60 );

bombaRapida = bombaLenta;

 

O que, a princípio, se espera é que ao atribuirmos bombaLenta a bombaRapida, a última fique com o valor da contagem regressiva de bombaLenta, certo ?

Bem, isso se esperava...

Como não declaramos um operador de atribuição, o compilador novamente se encarregou de fazê-lo por nós:

 

BombaRelogio& operator = (const BombaRelogio &bomba)
{
    return ( *this );
}

 

E esse operador default não implementa a funcionalidade que desejamos. Assim, a atribuição dos dois objetos não surtirá o efeito que esperamos dela.

O que se pode fazer, então, para que esta classe funcione sem estes tantos problemas ?

Restrinja o que seu código pode fazer.

Ao declarar uma classe, se você quer que ela possa ser construída pelo construtor padrão, declare-o. Senão desabilite-o.

Se você quer que o operador de atribuição funcione da maneira desejada, implemente-o. Senão desabilite-o.

Em C++, para desabilitar um construtor, um operador ou mesmo um método (de ser acessado), basta declará-lo fora da sessão pública.

Lembrando: Se quiser a possibilidade do acesso pelas classes filhas, declare-o como protegido. Senão declare-o como privado.

 

class BombaRelogio
{
public:
    BombaRelogio(const int contagemRegressiva)
    {
        _contagemRegressiva = contagemRegressiva;
        _relogio  = new Relogio;
    }
 
    ~BombaRelogio()
    {
        delete _relogio;
    }
 
    //...

protected:

    BombaRelogio()
    {
        _contagemRegressiva = 0;
        _relogio = new Relogio;
    }
 
 
    BombaRelogio& operator = (
      const BombaRelogio &bomba)
    {
        _contagemRegressiva =
           bomba.ContagemRegressiva;
 
        return ( *this );
    } 
};

 

Declarado assim, como protegido, você impede que um objeto de BombaRelogio possa ser instanciado sem receber a contagem regressiva e também impede de fazer atribuições entre objetos. Caso queira, declare os métodos como públicos.

Com estas simples ações, diversos tipos de problemas podem ser evitados. Portanto, acostume-se a executá-las. ;)

Generalizando:

  • Sempre declare um construtor sem parâmetros (default).
  • Sempre declare um operador de atribuição.

Se você quiser que um ou todos eles não sejam acessados, declare-os fora da parte pública.

 

A declaração de um operador de atribuição público leva à possibilidade de acrescentar à classe um construtor de cópia. Se você pode atribuir os valores de um objeto para outro, que tal você poder construir um objeto que seja um clone de um existente ?

 

BombaRelogio(const BombaRelogio &bomba)
{
    _relogio = new Relogio;
    *this = bomba;
}

 

Declarando mais este simples construtor, você adiciona a possibilidade de clonar objetos existentes:

 

BombaRelogio bombaRapida( 10 );
BombaRelogio bombaLigeira( bombaRapida );

 

Para completar os "requisitos" para uma classe com menos chance de problemas, aproveito para acrescentar este:

Acostume-se a declarar os destrutores como sendo virtuais.

Um destrutor ser virtual (assim como um método) significa que sua implementação pode ser redefinida em uma classe filha.

Acontece que, se você tiver uma classe pai que possua um destrutor não virtual e esse destrutor desaloque alguns objetos da memória, a classe filha terá de fazê-lo denovo. Isso porque o destrutor da classe pai não será executado após o da filha. Isso pode causar muitos problemas, sobretudo por esquecimento ou desconhecimento interno do objeto pai (desconhecimento esse que é até desejável). Sem falar nos casos em que a classe filha não pode nem mesmo acessar esses objetos que precisam ser desalocados, porque não possui acesso aos mesmos - se por exemplo, eles forem privados.

Logo, para evitar esse tipo de problema, sempre declare destrutores como sendo virtuais. Melhor serem e não precisar do que o contrário.

 

Conclusão

  • Restrinja o que seu código pode fazer.
  • Sempre declare um construtor sem parâmetros (default), mesmo que não seja público.
  • Sempre declare um operador de atribuição, mesmo que não seja público. Se for público, declare também um construtor de cópia, que faça uso do mesmo.
  • Sempre declare destrutores como sendo virtuais.

quinta-feira, 1 de fevereiro de 2007

Utilitário: Paint.NET

Nem um Photoshop, nem um Paint. Talvez um meio termo mesmo. Esse "Paint com esteróides" foi desenvolvido para ser leve, simples e intuitivo. E é exatamente assim, mesmo tendo uma boa gama de recursos, como camadas (layers), filtros, desfazer (undo) ilimitado com histórico, efeitos, etc.

 

 

 

 

 

 

 

 

 

 

O Paint.NET é opensource e requer o Microsoft.NET Framework 2.0. Em sua página de download há versões com e sem o framework.

terça-feira, 30 de janeiro de 2007

Dica C++: Onde constará o const ?

Olhe para este código:

 

char nome[] = "Mickey Mouse";

const char *pc = nome;

char *const cp = nome;

const char *const cpc = nome;

 

Sabe dizer ao certo o que as três últimas constantes declaradas significam, na prática ?

Uma dica: tenta lê-las da direita para esquerda.

Nos casos exemplificados, fica:

  • const char *pc pode ser lido como "pc é um ponteiro para um caractere constante".
  • char* const cp pode ser lido como "cp é um ponteiro constante para um caractere".
  • const char* const cpc pode ser lido como "cpc é um ponteiro constante para um caractere constante".

Vamos a explicação sintática, pra clarear mais o significado:

  • Colocando const antes de um ponteiro (*), você torna o objeto constante - e não o ponteiro. (Ex: const char *pc faz o valor do caracterer ser constante, não o ponteiro.)
  • Para o ponteiro ser constante, use *const.
  • Não existe const*.

Mas ora bolas - você pode estar perguntando - para que serve um objeto constante ? E para que um ponteiro constante ?

Sua utilidade principal é em parâmetros de funções. Quando você declara um objeto constante, ele não pode ser modificado pela função. Logo, como a função fica proibida de modificar o objeto, você tem a garantia que o objeto passado por parâmetro ficou intacto após ser manipulado pela mesma. Ex.:

void Imprimir(const char *linha);

(No exemplo, linha não poderá ser modificada pela função pois ela é uma constante.)

Já um ponteiro constante garante que o ponteiro não apontará para mais nenhum objeto além do que foi inicializado. Ex.:

 

int a = 10, b = 20, c = 30;
int *pa = &a;
int *const pb = &b;

*pa = 50; // OK - pode mudar o valor
*pb = 90; // OK - pode mudar o valor

pa = &c; // OK - pa pode apontar para outro
pb = &a; // ERRO - pb só pode apontar para b

 

Bem aplicado, isto pode auxiliar a evitar erros no código.

Veja o caso de acima introduzirmos um ponteiro constante para uma constante:

 

const int *const pc = &c;

*pc = 70; // ERRO - nao pode mudar o valor
pc = &a; // ERRO - nao pode apontar para outro

 

(Nem o valor do objeto apontado nem o objeto apontado podem mudar.)

Coisas assim, são úteis para tornar nosso código menos propenso a erros (limitando possibilidades de atribuições incorretas), evitando maiores dores de cabeça na hora da depuração.

domingo, 28 de janeiro de 2007

Truques com Baralho

Dez truques de mágica com baralho revelados. Nos vídeos (em inglês) é ensinado como fazer os truques:

Top 10 Magic Tricks Tutorial Videos

Aplicando Design by Contract

No último post sobre DbC, aprofundei seus conceitos e levantei algumas considerações necessárias para sua aplicação. Agora, introduzirei alguns exemplos práticos que permitirão materializar os conceitos vistos e dar início à prática de DbC.

 

DbC em linguagens que suportam nativamente

Em linguagens como EiffelD, existem estruturas na linguagem que permitem especificar formalmente um contrato.

Por exemplo, em D:

 

class Hora
{
    invariant
    {
        assert( _hora >= 0 && _hora <= 23 );
        assert( _minuto >= 0 && _minuto <= 59 );
        assert( _segundo >= 0 && _minuto <= 59 );
    };
 
    this(
      const int hora,
      const int minuto,
      const int segundo
      )
    {
        _hora = hora;
        _minuto = hora;
        _segundo = segundo;
    }
 
    this()
    {
        this( 0, 0, 0 );
    }
 
    ~this()
    {
    }
 
    int hora() { return ( _hora ); }
    void hora(int novaHora) { _hora = novaHora; }
 
    int minuto() { return ( _minuto ); }
    void minuto(int novoMinuto) { _minuto =         novoMinuto; }
 
    int segundo() { return ( _segundo ); }
    void segundo(int novoSegundo) { _segundo =     novoSegundo; } 
 
private:
    int _hora;
    int _minuto;
    int _segundo;
};

 

Aqui, a estrutura invariant definiu que os atributos privados _hora, _minuto e _segundo deverão sempre estar dentro de uma faixa de valores determinada, para todas as instâncias que a classe venha a ter. Enquanto algum método é executado, a verificação do contrato na invariant é desativado. Depois da execução, essas condições serão novamente verificadas.

Estas estruturas de invariáveis somente podem testar o valor de atributos e métodos que não sejam públicos. Para os métodos, caso haja a chamada de um método público dentro de um método privado, a chamada do último se tornará inválida para a invariável, gerando um erro.

Quanto a definição de contratos dentro de métodos, geralmente há uma estrutura como a exemplificada na linguagem D:

 

string Hora::FormatarComoString(
  const string &formato)
{
    in
    {
        // PRE-CONDICOES
        bool formatoValido =
          Formatador::FormatoHoraValido( formato );
  
        assert( formatoValido );
    }
    out
    {
        // POS-CONDICOES
    }
    body
    {
         // IMPLEMENTACAO DO METODO
  
        return ( Formatador::FormatarHora(
          *this, formato ) );
    }
}

A linguagem apresenta três blocos nos quais separa as pré-condições (in), pós-condições (out) e a implementação do método em si (body). Ambos os blocos de pré e pós-condições são opcionais, podendo ser declarados ou não. E ao compilar o programa em modo de liberação (release mode), o código destes dois blocos (ou seja, os contratos estabelecidos para o método) são automaticamente ignorados.

 

DbC em linguagens que não suportam nativamente

Nas demais linguagens, infelizmente estas estruturas não existem e, para implementarmos contratos, temos que usar de recursos específicos de cada linguagem e tentar simular o mesmo funcionamento.

Sobre pré e pós-condições, se a linguagem que estivermos usando possuir uma rotina como assert, podemos simulá-las:

// C++
string Hora::FormatarComoString(
  const string &formato)
{
    // PRE-CONDICOES ..............................
    bool formatoValido =
      Formatador::FormatoHoraValido( formato );
    assert( formatoValido );

    // IMPLEMENTACAO DO METODO ....................
    string resultado = Formatador::FormatarHora(
      *this, formato );

    // POS-CONDICOES ..............................
    // (validaria o resultado, caso preciso)
    // ............................................

    return ( resultado );

}

Repare que, diferente do exemplificado na linguagem D, em C++ tivemos de ter declarar as pós-condições após a implementação do método. O retorno do método só pode ser feito após a validação das pós-condições, caso hajam. Logo, o código deve ser implementado de forma a sempre poder fazer a validação das pós-condições - o que pode se tornar mais difícil quando o método precisa retornar após a validação de condições que não estão presentes no contrato. Neste caso, é preciso desviar a execução do código para o ponto onde as pós-condições são verificadas.

Com as invariáveis, é recomendado colocar as verificações dentro de um método virtual protegido (para poder ser redefinido por classes filhas) e chamar este método após as pós-condições:

// C++
string Hora::FormatarComoString(
  const string &formato)
{
    // PRE-CONDICOES ............................
    bool formatoValido =
      Formatador::FormatoHoraValido( formato );
    assert( formatoValido );

    // IMPLEMENTACAO DO METODO ..................
    string resultado = Formatador::FormatarHora(
      *this, formato );

    // POS-CONDICOES ............................
    // (validaria o resultado, caso preciso)    
       

    // INVARIAVEIS .............................        VerificarInvariaveis();
    // .........................................

    return ( resultado );   

}


// Metodo virtual protegido
void Hora::VerificarInvariaveis() const
{
    assert( _hora >= 0 && _hora <= 23 );
    assert( _minuto >= 0 && _minuto <= 59 );
    assert( _segundo >= 0 && _minuto <= 59 );
}

 

Há o incômodo de ter que acrescentar o método VerificarInvariaveis em cada método da classe. Porém esta é uma forma fácil de acrescentar invariáveis ao código de sua linguagem.

 

Considerações sobre outras possibilidades

Em algumas linguagens é ainda possível usar de outros artifícios para simular o mesmo comportamento de DbC em linguagens como D ou Eiffel. Em C++, por exemplo, há algumas bibliotecas que tentam simular este comportamento através de macros:

Veja #1#2 e #3.

Em Java, há um framework que através de classes de proxy dinâmico, captura definições à la DbC que são declaradas em comentários do código - no formato JavaDoc - e assim possibilitam introduzir fácilmente contratos ao código.

Há diversas opções, dependendo da linguagem escolhida, que possibilitam a introdução de contratos. Vale a pena procurar por formas simples e que contenham boa portabilidade.

Além de bibliotecas e frameworks que simulem DbC, há algumas que simplesmente focam no uso de assertivas. Um bom exemplo é a biblioteca SmartAssert (C++). Ela acrescenta diversas opções em relação ao assert usual e assim facilita muito as coisas para o programador.

Qualquer que seja a linguagem e suas possibilidades, há sempre uma forma de introduzir o conceito de contratos e assim melhorar a qualidade do código escrito.

 

 

sexta-feira, 26 de janeiro de 2007

Interfaces Alternativas

Alguns vídeos interessantes sobre outras formas de interação homem-pc:

Grid Interface
Multi-Touch Interface
Mixed Reality Interface
XGL Desktop for Linux
Spectasia 3D