Murilo :P

Computação, programação, web e afins :)

Posts Tagueados ‘cpp

Static Template Matrix – uma abordagem diferente

com 2 comentários

Static Template Matrix?

C++
De fato eu nunca vi esse nome em outro lugar, mas foi o nome que eu pensei que se aproxima mais da implementação que veremos nesse post.

Trata-se template de uma matriz (matrix) de duas dimensões de tamanho constante (static). Uma das diferenças dessa matriz é que ao invés de se usar o convencional operator[] para acessar os elementos, nessa abordagem iremos utilizar o operator().

Motivações

Na realidade, não tem muito mais utilidades práticas do que matrizes normais. Pode ser que pode servir em algo para você. Então minha motivação é puramente de aprendizagem, principalmente da linguagem.

matrix.h

#ifndef _CLASS_MATRIX_H__
#define _CLASS_MATRIX_H__

/**
 * matrix.h
 * Defines a template type 'matrix' wich is a constant-sized 2-dimensioned
 * 	matrix and generic typed elements.
 *
 * author: Murilo Adriano Vasconcelos
 * website: http://murilo.wordpress.com
 */

template
class matrix
{
    //data matrix
    T data[R][C];

    public:
    //type of the current matrix
    typedef matrix matrix_t;

    //quantity of rows
    const unsigned rows;
    //quantity of columns
    const unsigned columns;

    //default ctor
    matrix(): rows(R), columns(C) {};

    /*ctor wich initializes the matrix filled
      with 'value' elements */
    matrix(const T& value);

    //copy ctor: copies the matrix 'tocopy'
    matrix(const matrix_t& tocopy);

    /*gets and/or set the value of the element
      in the row 'i', column 'j' */
    T& operator()(unsigned i, unsigned j);

    /*gets the value of the element in the
      row 'i', column 'j' */
    const T& operator()(unsigned i, unsigned j) const;

    //copy operator
    matrix_t& operator=(const matrix_t& tocopy);
};

/* class functions definition */

    template
matrix::matrix(const matrix& tocopy): rows(R), columns(C)
{
    for (int i = 0; i < R; i++)
        for (int j = 0; j < C; j++)
            data[i][j] = tocopy(i, j);
}

    template
matrix::matrix(const T& value): rows(R), columns(C)
{
    for (int i = 0; i < R; i++)
        for (int j = 0; j < C; j++)
            data[i][j] = value;
}

template
    matrix&
matrix::operator=(const matrix& tocopy)
{
    for (int i = 0; i < R; i++)
        for (int j = 0; j < C; j++)
            data[i][j] = tocopy(i, j);

    return *this;
}

    template
T& matrix::operator()(unsigned i, unsigned j)
{
    return data[i][j];
}

template
const T& matrix::operator()(unsigned i, unsigned j) const
{
    return data[i][j];
}

#endif

main.cpp

#include "matrix.h" //our matrix
#include  //cout'ing
#include    //for strings

int main()
{
        //declares a 3x3 matrix filled with "nil"
        matrix mat("nil");

        //modifies the value in the position (1, 1) to C++
        mat(1, 1) = "C++";

        //we can use the const atribbutes rows and columns
        //to check our limits
        for (int i = 0; i < mat.rows; i++) {
                for (int j = 0; j < mat.columns; j++) {
                        //getting, setting the value of matrix elements
                        //is the same way
                        std::cout << mat(i, j) << ' ';
                }

                std::cout << '\n';
        }

        std::cout << '\n';

        matrix ones(1), identity;
        //copy
        identity = ones;

        //so silly
        for (int i = 0; i < identity.rows; i++) {
                for (int j = i; j < identity.columns; j++) {
                        if (i != j) {
                                identity(i, j) = identity(j, i) = 0;
                        }
                }
        }

        for (int i = 0; i < identity.rows; i++) {
                for (int j = 0; j < identity.columns; j++) {
                        std::cout << identity(i, j) << ' ';
                }

                std::cout << '\n';
        }

        return 0;
}

Como vocês puderam notar, a forma de acesso e modificação (get, set) dos elementos da matriz é da mesma forma. Outra coisa que podemos notar é que passamos o tipo e a quantidade de linhas e colunas direto no template. A quantidade de linha e colunas passada deve ser uma constante.

Bom, até mais.

obs.: Eu odeio profundamente o source highlight bugado do WordPress que converte todos os meus < e > e etc. para &lt; &gt;. Por isso os fontes acima não estão com hl.

Agora sim, até mais.

Escrito por Murilo Adriano

Segunda-feira 12 de Outubro de 2009 em 21:08

Publicado em C/C++, Estruturas de Dados, Programação

Etiquetado com , ,

C++: Uma introdução a Threads com boost::thread

com 2 comentários

boostPara quem ainda não conhece, Boost é um conjunto de bibliotecas C++ multiplataforma que trabalha bem com a STL e é muito bem aceita na comunidade. Já existem dez bibliotecas Boost incluídas no C++ TR1 e que estarão no C++0x além de muitas outras que estarão no C++0x e que atualmente não estão no TR1.

Para instalar o boost siga esse Getting Started.

Fazer threads com boost::thread é muito simples. Basta criar uma função ou um functor e passar pro construtor da classe boost::thread:

class functor
{
public: void operator()() {};
};

functor::operator()()
{
	/* content */
}

void function()
{
	/* content */
}

functor obj;
boost::thread tObj(obj); //passa uma cópia de obj
boost::thread tObjRef(boost::ref(obj)); //passa uma referência para obj
boost::thread tFunc(&funcao);

//inicia a execução das threads
tObj.join();
tObjRef.join();
tFunc.join();

//ou pode-se criar grupos de threads

boost::thread_group my_threads;
my_threads.create_thread(obj);
my_threads.create_thread(boost::ref(obj));
my_threads.create_thread(&function);

my_threads.join_all(); //inicia a execução de todas as threads desse grupo

Para ilustrar como funciona, fiz dois programinhas simples:

cin.cpp

#include <iostream>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>

//determina se o usuário já entrou com o número
bool flag = false;

struct in
{
	int n;

	in() : n(0) {};

	void operator()()
	{
		//try to read the number
		while (!(std::cin >> n)) {
			std::cin.clear();
			std::cin.ignore(10000, '\n');

			std::cout << "Enter a valid number" << std::endl;
		}

		flag = true;
	}

};

void my_alarm()
{
	while (!flag) {
		//shows the message
		std::cout << "Enter a number" << std::endl;

		boost::xtime time;
		boost::xtime_get(&time, boost::TIME_UTC); //current time

		time.sec += 5; //adds 5 secs to time
		//sleep 5 secs
		boost::thread::sleep(time);
	}

	//exiting function
	std::cout << "Alarm finished" << std::endl;
}

int main()
{
	in test;

	//create the two threads
	boost::thread tin(boost::ref(test));
	boost::thread tal(&my_alarm);

	//start
	tin.join();
	tal.join();

	//show the user's number
	std::cout << "Ok " << test.n << std::endl;

	return 0;
}

Esse programa é composto por duas threads (fora o fluxo principal) uma que é responsável por fazer a leitura de um número e a outra que fica a cada 5 segundos mostrando uma mensagem “Enter a number” enquanto o usuário não digitar um número válido. Quando o usuário digita um número válido, a flag é setada e os loops das duas threads são finalizados. Finalmente quando as duas threads são finalizadas, o fluxo normal de main() é reestabelecido e é mostrado o número digitado pelo usuário.

Lembrando que para usar boost::thread é necessário “linkar” a biblioteca ao programa. No caso do Linux é necessário linkar também a biblietca pthread em Windows “linkar” a win32api. No meu caso preferi usar linkagem estática.

murilo@blacksheep:~/programacao/boost$ g++ cin.cpp libboost_thread-gcc43-mt-1_39.a -o cin -lpthread
murilo@blacksheep:~/programacao/boost$ ./cin
Enter a number
Enter a number
naoehumnumero
Enter a valid number
Enter a number
4
Alarm finished
Ok 4

O outro exempo que fiz é um programinha que faz a multiplicação de duas matrizes e “simultaneamente” (depende de processador e SO) mostra uma barra de progresso com o progresso da operação.

multiplica.cpp

#include <iostream>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>

const int MAX = 1000;

int A[MAX][MAX];
int B[MAX][MAX];
int C[MAX][MAX];

int porcentagem = 0;

void multiplica()
{
	int soma;	

	for (int i = 0; i < MAX; i++) {
		for (int j = 0; j < MAX; j++) {
			soma = 0;
			for (int k = 0; k < MAX; k++) {
				soma += A[i][k] * B[k][j];
			}

			C[i][j] = soma;
		}
		if (i % 10 == 0) porcentagem++;
	}
}

void barra_de_progresso()
{
	int atual = 0;
	while (porcentagem != 100) {
		if (atual != porcentagem) {
			if (porcentagem % 10 == 0) {
				std::cout << "\b\b" << porcentagem << '%';
			}
			else std::cout << '=' << std::flush;

			atual++;
		}
	}
}

int main()
{
	boost::thread tMultiplica(&multiplica);
	boost::thread tProgresso(&barra_de_progresso);

	boost::xtime inicio, fim;
	boost::xtime_get(&inicio, boost::TIME_UTC);

	std::cout << "Iniciando a multiplicação de matrizes" << std::endl;

	tMultiplica.join();
	tProgresso.join();

	boost::xtime_get(&fim, boost::TIME_UTC);

	std::cout << "\n\nProcesso terminado em " <<
		(fim.sec - inicio.sec) << " segundos" << std::endl;

	return 0;
}

Saída:

murilo@blacksheep:~/programacao/boost/thr$ g++ multiplica.cpp libboost_thread-gcc43-mt-1_39.a -lpthread -o multiplica
murilo@blacksheep:~/programacao/boost/thr$ ./multiplica
Iniciando a multiplicação de matrizes
=======10%=======20%=======30%=======40%=======50%=======60%=======70%=======80%=======90%=======100%

Processo terminado em 43 segundos

Claro que o que menos nos importa nesse momento é o valor das matrizes e a multiplicação em si, por isso nem me dei ao trabalho de inicializar as matrizes nem de fazer nada com a matriz resultante.

Acredito que para uma introdução está bom e deu pra mostrar como é fazer programas com boost::thread com esses simples exemplos. Mais exemplos você pode encontrar na pasta libs do boost.

Links:

Escrito por Murilo Adriano

Quinta-feira 6 de Agosto de 2009 em 18:06

Publicado em C/C++, Programação

Etiquetado com , , ,

Coisas simples de se fazer em C++ que alguns ainda complicam #1 – Imprimir valores de contêineres STL

sem comentários

Bom, vou fazer uma série de posts dizendo sobre coisas simples de se fazer em C++ que muitos ainda complicam. A idéia surgiu do post de um colega.

O primeiro post dessa série é sobre como imprimir facilmente todos os valores de um contêiner STL.

Iremos usar para isso, ostream_iterators que fornecem iterators para escrita em streams de saída. ostream_iterator está declarado em .

Vamos ao nosso exemplo:

#include <iostream> //para cout
#include <iterator> //para ostream_iterator
#include <vector>

using namespace std;

int main()
{
        vector<int> v(5);
        v[0] = 1;
        v[1] = 1;
        v[2] = 2;
        v[3] = 3;
        v[4] = 5;

        //copia todo o vetor [begin() -> end()) pro cout com um  ", " de delimitador
        copy(v.begin(), v.end(), ostream_iterator<int>(cout, ", "));
}

Resultado:


1, 1, 2, 3, 5,

A seguir um exemplo mais funcional, um gerador de arquivos CSV. Ao invés de usarmos o ostream_iterator(cout, ","), utilizaremos ostream_iterator(arquivo, ";") que diz que que queremos passar strings para serem escritas em um arquivo de texto com o delimitador ";":

#include <fstream> //para ofstream
#include <iostream> //para cerr
#include <iterator> //para ostream_iterator
#include <vector>
#include <string>

#define DELIMITADOR ";"

using namespace std;

int main()
{
        typedef vector< vector<string> > vvs;
        vvs csv(3); 

        //preenchendo
        vector<string> v;
        v[0] = "'Murilo Adriano'";
        v[1] = "'muriloufg(at)gmail(dot)com'";
        v[2] = "8888-8888";
        v[3] = "'murilo.wordpress.com'";
        csv[0] = v;

        vector<string> v2(4);
        v2[0] = "'Outra Pessoa'";
        v2[1] = "'outoemail(at)outrohost(dot)com'";
        v2[2] = "9999-9999";
        v2[3] = "'website.com'";
        csv[1] = v2;

        vector<string> v3(4);
        v3[0] = "'Foo Bar'";
        v3[1] = "'foo(at)bar(dot)com'";
        v3[2] = "0000-0000";
        v3[3] = "'foobar.com'";
        csv[2] = v3;       

        //tenta abrir o arquivo
        ofstream arquivo("planilha.csv");
        if (arquivo.is_open()) {
                vvs::iterator it;
                for (it = csv.begin(); it != csv.end(); it++) {
                        //escreve os elementos de cada item do vetor no arquivo
                        copy((*it).begin(), (*it).end(),
                                ostream_iterator<string>(arquivo, DELIMITADOR));

                        //quebra uma linha
                        arquivo << '\n';
                }

                arquivo.close(); // fecha o arquivo
        }
        else {
                //se não foi possível abrir o arquivo
                cerr << "Falha ao abrir o arquivo\n" << endl;
        }
}

Após rodar o programa, abra o arquivo gerado no seu software de planilha eletrônica preferido e veja o resultado:

Arquivo gerado

Arquivo gerado pelo programa acima aberto no OpenOffice

É isso aí pessoal, nos próximos posts exploraremos mais o C++ e STL.
Até a próxima.

Escrito por Murilo Adriano

Domingo 26 de Julho de 2009 em 14:21

Publicado em C/C++, Programação

Etiquetado com , , , , , ,

Sobrecarga do operator++ para enums

com um comentário

Mais uma trick com enums.

A sobrecarga de operadores podem facilitar o manuseio de enums. Abaixo está um exemplo de como pode ser útil a sobrecarga do operator++.

#include <iostream>

using std::cout;
using std::endl;

enum Semana
{
        DOM,
        SEG,
        TER,
        QUA,
        QUI,
        SEX,
        SAB
};

Semana& operator++(Semana& dia) //pré-incremento
{
        return dia = static_cast<Semana>((dia + 1) % 7);
}

Semana& operator++(Semana& dia, int) //pós-incremento
{
        return dia = static_cast<Semana>((dia + 1) % 7);
}

int main()
{
        Semana dia = SEX;
        cout << dia << endl; // SEX (5)
        cout << ++dia << endl; // SAB (6)
        cout << ++dia << endl; // DOM (0)
        dia++; // SEG (1)
        cout << dia << endl;
}

Quando chegamos no último dia da semana (SAB) e chamamos o operator++, obtemos o primeiro dia da semana graças ao operador módulo (%).

Referência.

Escrito por Murilo Adriano

Sábado 25 de Julho de 2009 em 00:35

Publicado em C/C++, Programação

Etiquetado com , , ,

O que são enums e como utilizá-los melhor em C++

com 7 comentários

C++

O que são os enums (C e C++)

Um enum (enumeração) é um tipo definido pelo usuário (programador) que consiste em constantes do tipo int nomeadas.

Um jeito tradicional de se declarar constantes em C e C++ é o seguinte:

#define BRASIL 0
#define ITALIA 1
#define PORTUGAL 2
#define ALEMANHA 3

E eis a maneira de fazer o mesmo utilizando enums:

enum
{
        BRASIL,
        ITALIA,
        PORTUGAL,
        ALEMANHA
};

Pode-se, alternativamente, criar um tipo para seu enum:

enum Paises
{
        BRASIL,
        ITALIA,
        PORTUGAL,
        ALEMANHA
};

E declarar uma variável desse tipo com:

Paises pais; //C++ apenas
enum Paises pais; //C e C++

Num enum igual a esses acima, a primeira constante recebe o valor 0 e as subsequentes recebem o valor da constante anterior mais 1. Ou seja, BRASIL é 0, ITALIA é 1, PORTUGAL é 2 e ALEMANHA é 3.
Podemos também atribuir valores manualmente às constantes como em:

enum Paises
{
        BRASIL = 2,
        ITALIA,  //ITALIA é igual a 3 (2 + 1)
        PORTUGAL = 1,
        ALEMANHA  //ALEMANHA é igual a 2 (1 + 1)
};

Como podemos perceber no exemplo anterior, a mesma regra se aplica para os enums com valores manuais, o que não tiver um valor explicitamente inserido receberá o valor do anterior somado em 1. Percebemos também que podem haver constantes com o mesmo valor (BRASIL == ALEMANHA == 2).

Conversão

A conversão de uma constante de um enum para um inteiro por exemplo é feita automaticamente. Já o contrário não deve ser permitido pelo compilador.

enum Paises
{
        BRASIL,
        ARGENTINA,
        VENEZUELA
};

...

int inteiro = VENEZUELA + 2; //4
Paises pais = 3; //ERRO

Uma melhor maneira de usar enums em C++

Veja o exemplo:

enum Paises
{
        BRASIL,
        ITALIA,
        ALEMANHA
};

enum Uvas
{
        RUBI,
        ITALIA,
        UMOUTROTIPODEUVA
};

Isso irá ocasionar um erro porque ITALIA já foi definido. A saida do meu compilador (g++ 4.3.2) foi a seguinte:

murilo@blacksheep:~/$ g++ enums.cpp
enums.cpp:14: error: conflicting declaration ‘ITALIA’
enums.cpp:8: error: ‘
ITALIA’ has a previous declaration as ‘Paises ITALIA’

Mas e agora?? Eu quero ter dois enums diferentes que representam coisas diferentes mas que podem ter a mesma constante. Como?

A resposta é namespaces!
Em C++ podemos declarar nossos enums dentro de namespaces e assim termos as constantes em espaços de nomes diferentes. Nada de conflito agora hein g++!!!

namespace Paises
{
        enum
        {
                BRASIL,
                ITALIA,
                ALEMANHA
        };
}

namespace Uvas
{
        enum
        {
                RUBI,
                ITALIA,
                UMOUTROTIPODEUVA
        };
}

//*...*//
//Modo de uso:

std::cout << Uvas::ITALIA;
std::cout << Paises::ITALIA;

É isso aí galera, até a próxima.

Escrito por Murilo Adriano

Sexta-Feira 29 de Maio de 2009 em 01:28

Publicado em C/C++, Programação

Etiquetado com , , ,

Como implementar facilmente getters e setters em C++

com 5 comentários

Se você é como eu que odeia ficar digitando dois métodos para cada atributo que você cria em sua classe, seus problemas acabaram.
Trata-se de uma macro feita através de um #define mesmo que facilita muito a vida dos programadores OO em C++.
Vejamos a macro:

#define declare(type, name) \
private: type _##name; \
public: \
void set##name(const type& var) \
{\
        _##name = var;\
}\
\
type get##name() \
{\
        return _##name; \
}\

Leia o resto deste post »

Escrito por Murilo Adriano

Quinta-feira 21 de Maio de 2009 em 13:27

Publicado em C/C++, Programação

Etiquetado com ,

Define para fácil alocação de matrizes em C++

sem comentários

C++Houve uma questão na comunidade C e C++ Brasil no Orkut sobre alocação de matrizes em C++ e resolvi fazer algo para facilitar a alocação delas.

Nada de algo complicado, trata-se do simples #define abaixo:


#define matalloc(t, x, y, z) \
x = new t*[y]; \
for (int i = 0; i < y; i++) x[i] = new t[z];

Onde:

  • t é o tipo dos elementos da matriz;
  • x é a variável (ponteiro pra ponteiro) que receberá a matriz;
  • y é a quantidade de linhas que a matriz terá;
  • z é a quantidade de colunas.

Uso:

#include
using namespace std;

#define matalloc(t, x, y, z) \
x = new t*[y]; \
for (int i = 0; i < y; i++) x[i] = new t[z];

int main()
{
int** x;
matalloc(int, x, 3, 3);

x[0][0] = 2;
x[1][2] = 4;

cout &lt;&lt; x[0][0] &lt;&lt; &quot; &quot; &lt;&lt; x[1][2] &lt;&lt; endl;
}

Exemplo:

http://codepad.org/KoeN1d9j

Escrito por Murilo Adriano

Sexta-Feira 6 de Março de 2009 em 18:26

Publicado em C/C++, Programação

Etiquetado com , ,

Comparação de desempenho: std::vector vs Array

com 2 comentários

C++Comparação entre os códigos assembly gerados para operações de indexação básica, dereferenciação eincremento em std::vectors e arrays/ponteiros.

O código assembly foi gerado pelo gcc 4.1.0 chamado com g++ -03 -S em uma máquina x86_64-suse-linux.

#include 

struct S
{
  int padding;

  std::vector v< int >;            //nosso vector
  int * p;                    //nosso ponteiro
  std::vector< int >::iterator i; //iterador do vector
};

int indexar_ponteiro(S & s) { return s.p[3]; }
  // movq    32(%rdi), %rax
  // movl    12(%rax), %eax
  // ret

int indexar_vector(S & s) { return s.v[3]; }
  // movq    8(%rdi), %rax
  // movl    12(%rax), %eax
  // ret

// Conclusão: Indexar um std::vector é a mesma coisa de indexar um ponteiro.

int deref_ponteiro(S & s) { return *s.p; }
  // movq    32(%rdi), %rax
  // movl    (%rax), %eax
  // ret

int deref_iterador(S & s) { return *s.i; }
  // movq    40(%rdi), %rax
  // movl    (%rax), %eax
  // ret

// Conclusão: Dereferenciar um std::vector é a mesma coisa de dereferenciar um ponteiro.

void incrementar_ponteiro(S & s) { ++s.p; }
  // addq    $4, 32(%rdi)
  // ret

void incrementar_iterador(S & s) { ++s.i; }
  // addq    $4, 40(%rdi)
  // ret

// Conclusão: Incrementar um iterador de std::vector é a mesma coisa de incrementar um ponteiro.

Ou seja, além das facilidades do std::vector, algumas operações básicas tem o mesmo custo tanto com std::vector quanto um array/ponteiro.

Surpreso?

Escrito por Murilo Adriano

Quarta-feira 14 de Janeiro de 2009 em 21:57

Publicado em Baixo nível, C/C++, Programação

Etiquetado com , ,

Smart Pointers: Os Ponteiros Espertos do C++

com 2 comentários

C++E aí pessoal, como prometido, vou falar sobre Smart Pointers em C++.
Neste post irei abordar smart pointers, o que são, como funcionam e para que são usados, além de mostrar um exemplo de implementação de smart pointers.

1. Introdução:

O que são Smart Pointers?

Smart pointers são implementações feitas para facilitar e ajudar no manuseamento de ponteiros. Para serem mais “inteligentes” que os ponteiros normais, os smart pointers precisam fazer coisas que os ponteiros normais não fazem. Leia o resto deste post »

Escrito por Murilo Adriano

Segunda-feira 15 de Dezembro de 2008 em 14:18

Publicado em C/C++, Estruturas de Dados, Programação

Etiquetado com ,

Linguagens de programação – C++ – Direito de defesa

com 27 comentários

C++Um dia desses passeando por blogs ví um post que me chamou a atenção. O título é Linguagens de programação – C++ e, claro, chamou minha atenção, não apenas por causa do post assim com também por causa dos comentários sobre o post.

O objetivo desse post não é gerar um flame, até porque não atacarei nenhuma linguagem, só dissertarei sobre fatos.

Leia o resto deste post »

Escrito por Murilo Adriano

Sexta-Feira 14 de Novembro de 2008 em 01:12

Publicado em C/C++, Programação

Etiquetado com , , ,