Posts Tagueados ‘cpp’
Static Template Matrix – uma abordagem diferente
Static Template Matrix?

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 < >. Por isso os fontes acima não estão com hl.
Agora sim, até mais.
C++: Uma introdução a Threads com boost::thread
Para 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:
Coisas simples de se fazer em C++ que alguns ainda complicam #1 – Imprimir valores de contêineres STL
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:
É isso aí pessoal, nos próximos posts exploraremos mais o C++ e STL.
Até a próxima.
Sobrecarga do operator++ para enums
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 (%).
O que são enums e como utilizá-los melhor em 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.
Como implementar facilmente getters e setters em C++
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; \
}\
Define para fácil alocação de matrizes em 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 << x[0][0] << " " << x[1][2] << endl;
}
Exemplo:
Comparação de desempenho: std::vector vs Array
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?
Smart Pointers: Os Ponteiros Espertos do 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 »
Linguagens de programação – C++ – Direito de defesa
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.
