martes, 5 de noviembre de 2013

Como trabajar con CMake en Eclipse?

Hacia tiempo que queria cambiar otra vez a eclipse, por que aunque netbeans me gusta, lo encuentro limitado. La ventaja que tiene netbeans es su soporte nativo para CMake. En cambio, con eclipse tenia que limitarme a escribir mi archivo CMakeLists.txt y crear el makefile para despues incluirlo en eclipse. Hace poco encontré una manera alternativa de usar CMake desde dentro de eclipse que completaba la cadena. Vamos a ver como se hace

1.- Crear un nuevo proyecto

Creamos un nuevo proyecto C/C++ en eclipse desde 0. Es decir, no usamos la opción de crear un "Makefile Project with Existing Code".
Le vamos a añadir codigo fuente de ejemplo:
main.cpp
#include "main.h"
int main() {
); return EX
greetings (IT_SUCCESS;
}
main.h
#include <iostream>
void greetings() {
a" << std::endl; }
std::cout << "Ho
l
Ademas del código vamos a añadir un CMakeLists.txt directamente en eclipse.
cmake_minimum_required(VERSION 2.8)
project(cmake_test) SET( TEST_SRC
rc/main.h ) add_executable(te
src/CMakeInEclipseTest.cpp
sst_common ${TEST_SRC})



2.- Creando los targets de eclipse

Vamos a aprovechar que podemos ejecutar instrucciones de CMake desde linea de comandos con la opcion -E para usarlo con los targets de eclipse. Primero vamos a ver la ventana de Make Target en Window | Show View | Make Target . Debe aparecer a la derecha.


Ahora seleccionamos la carpeta que sera la carpeta de trabajo de CMake. Hacemos click derecho y seleccionamos Create Make Target.
Vamos a ponerle un nombre a este target CMake Release
En la ventana Make Target, quitamos la selección "Same as the target name", y nos aseguramos que el campo este vacio.


En build command, deseleccionamos Use Builder settings y escribimos en build command algo como
cmake -E chdir ${ProjDirPath}/build/Release/ cmake -G "Unix Makefiles" ../../ -DCMAKE_BUILD_TYPE:STRING=Release

En este momento quedaria asi.
Lo que intento es que el código intermedio y caches generadas por cmake quede en una carpeta "build" para que no ensucie la carpeta de proyecto. Dentro de buid estará "Release" y "Debug" donde se generan las versiones correspondientes. 

Para probarlo, nos aseguramos de que  ${ProjDirPath}/build/Release existe y si hacemos doble click deberiamos ver en la consola de Eclipse la ejecución de CMake.

Podemos crear más targets que perfilen la construcción del proyecto (Debug, con diferentes flags, ...)





3.- Configurar el Eclipse CDT Builder

Hacemos click derecho en el proyecto y vamos a las preferencias. Vamos a C/C++ Build y y alli seleccionamos Configuration: [All configurations]. Seleccionamos la pestaña Builder Settings  y quitamos el check de Use default build command. En build command ponemos make -C build/${ConfigName} . Desactivamos Generate Makefiles automatically y dejamos en blanco Build directory. En resumen quedaria algo asi: 

La pestaña de bahaviour la dejamos igual. Le damos a apply y a OK y ahora nos vamos project -> build project  y vemos como el proyecto se construye. Con esto deberiamos tener toda la cadena CMake + Make + codigo en funcionamiento en nuestro Eclipse.

miércoles, 7 de marzo de 2012

Run-Time Type Information

Pues sigo con mi motor y lo que he hecho ahora es darle la capacidad a las clases de obtener información sobre su tipo. Esta técnica se puede activar por compilador pero es poco portable y muy ineficiente (por que se activa para todas las clases y con soporte para herencia múltiples). En mi caso lo hago restringiendo a herencia simple y solo para las clases que hereden de object. El UML es este:
Uso object como concentrador de utilidades que le voy dando a todo el resto de clases del motor, asi que rtti no se usa directamente sino a traves de objet. El codigo es este:
class Rtti
{
public:

    Rtti (const char* name, const Rtti* baseType);
    ~Rtti ();

    inline const char* GetName () const;
    inline bool IsExactly (const Rtti& type) const;
    bool IsDerived (const Rtti& type) const;

private:
    const char* m_name;
    const Rtti* m_baseType;
};
Como ves el nombre del tipo va en name y el tipo de la base es un puntero a una clase de tipo Rtti. Cuando queremos saber el tipo de una clase solo tenemos que hacer:
nombreClase::Rtti::GetName();
Y podemos saber si una clase es de un tipo asi:
if( objeto1::Rtti.IsExactly( objeto2::Rtti ) )
o tambien asi
if( objeto1.GetRttiType().IsExactly( objeto2.GetRttiType() )
Es en el objeto zelObject donde pongo el objeto Rtti para que lo hereden el resto de clases:
class zelObject
{
// Run-time type information.
public:
    virtual const Rtti& GetRttiType () const;
    bool IsExactly (const Rtti& type) const;
    bool IsDerived (const Rtti& type) const;
    bool IsExactlyTypeOf (const zelObject* object) const;
    bool IsDerivedTypeOf (const zelObject* object) const;
    static const Rtti TYPE;


// Abstract base class.  Construction and destruction.
protected:
    zelObject ();
public:
    virtual ~zelObject ();

};
Como ves el objeto Rtti se declara como static por que no hay necesidad de repetir esta información en cada instancia. Como cada clase tiene su propio objeto Rtti, el constructor escribirá en su propia instancia estatica el nombre de la clase. Para ayudar a que la declaracion sea menos tediosa incluyo estas macros:
//----------------------------------------------------------------------------
#define RTTI_DECLARATION \
public: \
    static const Rtti TYPE; \
    \
    virtual const Rtti& GetRttiType () const \
    { \
        return TYPE; \
    }
//----------------------------------------------------------------------------
#define RTTI_IMPLEMENTATION(nsname, baseclassname, classname) \
    const Rtti classname::TYPE(#nsname"."#classname, &baseclassname::TYPE)
//----------------------------------------------------------------------------
que delcaran el Rtti en cada clase como public(para sobreescribir en cada clase la declaración) e inicializar la variable estatica on el nombre de clase con su namespace, y el tipo. Pero para que tanto rollo? Entre otras cosas para poder hacer dynamic_cast sin tener que activar el rtti. Y que consigo con esto? Pues mi siguiento paso es la serialización, pero esto ya lo contaré más adelante.

jueves, 23 de febrero de 2012

La pila

Si quieres sentir la libertad de programar en C/C++ y tener control sobre todos los recursos de la aplicación, debes aceptar la responsabilidad de conocerlos por que sino las consecuencias pueden ser bugs escurridizos de verdad. Mira este:

#include <iostream>
#include <sstream>

using namespace std;
unsigned int* theFunction(unsigned int b)
{
 unsigned int a = 33 + b;
 return &a;
}

std::string getMessage(int a)
{
 string bb = "El valor de la variable a es: ";
 stringstream ss;
 ss << bb << a << "\n";
 return ss.str();
}

int main()
{
 int mi_variable = 40;
 unsigned int* a = theFunction(mi_variable );
 if(*a > 55)
 {
  string msg( getMessage(*a));
  cout << msg << endl;
 }
 cout << "El resultado es "<< 31 + *a << endl;
 system("PAUSE");
 return EXIT_SUCCESS;
}

Si lo compilas y lo pruebas no fallará, pero si le cambias e valor a mi_variable y juegas un poco con su valor al final fallará algo. Pero que ha pasado?
Cuando un programa un programa se inicia, reserva un trozo de memoria que se llama “pila de programa” (programa stack). Para que se usa? Cada vez que un programa llama a una función, el programa usa un trozo de memoria contigua (llamado stack frame), y en ella coloca lo que necesita para que la función se ejecute: por un lado alli pone la direccion de retorno, o sea, la dirección donde el programa debe ir cuando se acabe la función. Por otro lado reserva espacio para las variables que se usan en la función. En tercer lugar, salva el contenido de los registros del procesador que sean relevantes. Por ejemplo, en la siguiente función:

int f()
{
 unsigned int a = 0;
 double b = 1.00;
 g();
 return a;
}
el sistema reservaria un espacio para guardar la dirección de retorno (seguramente una palabra de memoria, de 32bits en SO de 32bits), otra para palabra para el unsigned int y dos palabras para el double. Además tambien guardaria los registros necesarios para continuar la ejecución del código que llama a f() una vez finalice. Que pasa con g(), pues que el sistema vuelve a usar otro trozo de memoria de la pila para ejecutar g(). Cuando acaba g() vuelve a f().

El valor que retorna f() se guarda en un registro para que esté alli cuando el código que llamó a f() se continúe ejecutando. Esta estructura es muy conveniente para el sistema. Por un lado no tiene que buscar un trozo de memoria conveniente sino que simplemente usa el siguiente al que tiene. Además, cuando acaba con la función simplemente abandona el trozo de memoria usado sin hacer ninguna limpieza, con lo que se gana velocidad y simplicidad a partes iguales.

Entonces, que ha pasado en el código del principio?
En el momento en que se sale de la función, esa zona de la memoria queda “abandonada” pero el valor de “a” no se pierde por que el sistema no hace ninguna limpieza. Si mi_variable es menor que 22, no pasa nada por que no entramos en el “if”, y por tanto no llamamos a la función getMessage. Asi que el valor final es correcto. En cambio, a partir de 22, entramos en el if y por tanto llamo a getMessage. Eso provoca que el sistema use el espacio contiguo de memoria, donde estaba el valor de a, y sobreescribe, “pisando” el valor de “a”.

Lo peor de todo es que no da ninguna excepción (en el momento de la compilación tira un warning que, como siempre, no deberías ignorar), pero nos mostrará el valor que tenga la memoria en ese momento que puede ser cualquiera, provocando un bug que puede llegar a ser escurridizo como él solo. Asi que cuando juegues con c++, recuerda que un gran poder conlleva una gran responsabilidad (o diversión, siempre que te guste cazar bugs, claro :) )

Espero que con esta entrada hayas entendido algo más sobre la pila. En otra entrada hablaremos un poco sobre el heap, o montón.

lunes, 20 de febrero de 2012

Programacion orientada a tests (TDD)

Como estoy volviendo a programar sobre mi motor y he eliminado un montón de código, ahora tengo que repetir algunas clases y añadir otras. He estado mirando algunos paradigmas de programación y hay uno que llamó poderosamente mi atención que es la programacion orientada a test o “test driven development”. 

Hace un tiempo publiqué una entrada sobre las bondades de los test unitarios, pero la verdad es que cuando profundizas en ellos, te acabas preguntando indefectiblemente: “para que quiero hacer test sobre un código que ya esta acabado?” y tambien uno se pregunta “si ya se como funciona ese metodo (por que yo mismo lo he programado), por que voy a probarlo?” También hay gente que se pregunta si no es una herramienta de calidad usada por programadores. He invertido algún tiempo en leer cosas sobre el tema y puedo decir que no. TDD es una herramienta que abarata costes de producción porque reduce los bugs y sobretodo el tiempo que tardamos en encontrarlos. Pero ademas sirve para entender el código. Nunca te has bajado un código que no entiendes? Sabes que si lo tocas en el punto A vas a romper algo en el punto B (donde B puede ser cualquier lugar). Una manera de ahcer cambios en el código es escribir test unitarios para ver si realmente entendemos lo que hacemos. Si falla es que no lo entendemos. Si sale verde es que entendemos esa pieza de código.

En TDD debemos diseñar, escribir los tests (testear) y despues desarrollar. Los pasos serian:

  1. Escribimos el test case unitario 
  2. Lanzamos los test unitarios escritos hasta ahora 
  3. Si sale verde (todos los test OK), no hacemos nada más. Nuestro trabajo ha acabado a menos que salgan nuevos requisitos 
  4. Si sale rojo aplicamos la solución más sencilla que se nos ocurra y nos lleve al verde. 
  5. Volvemos al punto 2. 


Es importante señalar que en este proceso solo podemos estar haciendo una de estas 3 cosas: programar tests unitarios nuevos, programar funciones que satisfagan los test unitarios, haciendo refactoring para reducir duplicidad de código. Este último punto se da por la regla de programar siempre la solución más sencilla. Recuerda que cada vez que tocamos código debemos lanzar otra vez nuestro conjunto de test unitarios. Un ejemplo: imaginemos que tenemos que hacer parte de una calculadora donde entra un string con una operación matemática y tu devuelves un int que representa el resultado de la operacion o lanzas una excepción en caso de error. Es válido estas operaciones:
“1 + 2” y devolvemos 3
“5 - 3” y devolvemos 2
“3” y devolvemos 3
“” y devolvemos 0

Este ejemplo lo he sacado de aqui: http://sajdak.eu/trainings/agile-cpp-developer/google-test/first-and-easy-but-real-test/ Antes de seguir leyendo, intenta pensar en como programarias una función asi: Lo primero que hacemos es crear uno de los test cases unitarios
TEST(text_calculator,001_empty_string_returns_zero)
{
	CText_calculator tc;
	ASSERT_EQ(0, tc.calculate(""));
}
Ejecutamos los test y ni siquiera compilan, por que no existe la funcion. Pero ya hemos ejecutado y cada ejecución nos puede servir de barrera para “cambiar de sombrero” de programador de aplicacion a programador de test. Asi solo tocamos una cosa cada vez. Recuerda que la idea es implementar la idea más sencilla que se nos ocurra.
#pragma once
#include "string"

class CText_calculator
{
public:
	int calculate(const std::string& op)
	{
		return 0;
	}
	CText_calculator(void){}
	~CText_calculator(void){}
};
Volvemos a ejecutar los test cases y … “verde!!!” Ya cumplimos el primer requisito. Vamos a escribir otro test con el segundo requisito
TEST(text_calculator, cadena_vacia_devuelve_cero)
{
	ASSERT_EQUALS(text_calculator(“3”), 3);
}
Ejecutamos y evidentemente los tests fallan.
Running main() from gtest_main.cc
[==========] Running 2 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 2 tests from text_calculator
[ RUN      ] text_calculator.001_empty_string_returns_zero
[       OK ] text_calculator.001_empty_string_returns_zero (0 ms)
[ RUN      ] text_calculator.002_literal_3_returns_3
c:\directo\mypgp\blog_to_tes\text_calculator_test\text_calculator_test\test_case
s.cpp(13): error: Value of: tc.calculate("3")
  Actual: 0
Expected: 3
[  FAILED  ] text_calculator.002_literal_3_returns_3 (0 ms)
[----------] 2 tests from text_calculator (0 ms total)

[----------] Global test environment tear-down
[==========] 2 tests from 1 test case ran. (0 ms total)
[  PASSED  ] 1 test.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] text_calculator.002_literal_3_returns_3

 1 FAILED TEST
Presione una tecla para continuar . . .
Falla cocretamente el test del 3. Vamos a meter unos if
	int calculate(const std::string& op)
	{
		if(op == "")
			return 0;
		if(op == "3")
			return 3;
	}
Al ejecutar, todos los test van bien. Pero como el requisito no es meterle “3” sino cualquier numero, vamos a crear un test mas amplio:
TEST(text_calculator,003_literal_always_return_the_number_that_represents)
{
	CText_calculator tc;
	srand(time(NULL));
	int generated = rand() % 1000 + 1;
	std::stringstream out;
	out << generated;

	ASSERT_EQ(generated, tc.calculate(out.str()));
}
Ejcutamos el test y falla. Además vemos que con un if no vamos a ninuna parte, asi que modificamos el código de otra manera:
#pragma once
#include "string"
#include "sstream"

class CText_calculator
{
public:
	int calculate(const std::string& op)
	{
		if(op.size() == 0)
			return 0;
		
		int result;
		std::stringstream(op) >> result;
		return result;
	}

	CText_calculator(void){}
	~CText_calculator(void){}
};

Ahora volvemos a ejecutar y todo va bien, da igual el número que le metamos. Vamos ahora con las operaciones de dos operandos. Lo primero, escribir el test correspondiente:
TEST(text_calculator,004_3_plus_5_always_returns_6)
{
	CText_calculator tc;
	ASSERT_EQ(8, tc.calculate("3 + 5"));
}
Para resolverlo puedo se me ocurre que primero podria mirar si hay un ‘+’ y entonces ya sabria que es una operacion de dos operandos:
#pragma once
#include "string"
#include "sstream"

class CText_calculator
{
public:
	int calculate(const std::string& op)
	{
		if(op.size() == 0)
			return 0;
		
		int result;
		std::stringstream ss(op);
		ss >> result;

		size_t operator_pos = op.find("+");
		if(operator_pos == std::string::npos)
			return result;
		std::string second_op(op.substr(operator_pos + 1));
		int result2 ;
		std::stringstream ss2(second_op);
		ss2 >> result2;
		return result2 + result;


	}

	CText_calculator(void){}
	~CText_calculator(void){}
Los test pasan perfectamente pero veo varias cosas. La primera que el codigo de convertir strings a int se repite, y el codigo repetido casi siempre hay que evitarlo. Vamos a hacer refactoring. Este es otro gran uso del TDD. Si primero, antes de hacer refactor, escribimos los test y nos aseguramos que pasan, despues solo tenemos que ejecutar los test cases despues de cada cambio del refactoring para darnos cuenta si falla algo. El resultado de separa la función de pasar de string a numero es esta:
#pragma once
#include "string"
#include "sstream"

class CText_calculator
{
private:
	int str_to_number(const std::string& str)
	{
		int result;
		std::stringstream ss(str);
		ss >> result;
		return result;
	}
public:
	int calculate(const std::string& op)
	{
		if(op.size() == 0)
			return 0;
		
		int number1 = str_to_number(op);

		size_t operator_pos = op.find("+");
		if(operator_pos == std::string::npos)
			return number1;

		std::string second_op(op.substr(operator_pos + 1));
		int number2 = str_to_number(op.substr(operator_pos + 1));
		return number1 + number2;
	}

	CText_calculator(void){}
	~CText_calculator(void){}
};
Ahora ya puedo escribir otro caso de test:
TEST(text_calculator,004_5_minus_3_always_returns_2)
{
	CText_calculator tc;
	ASSERT_EQ(2, tc.calculate("5 - 3"));
}
Y al ver que falla aplicar los cambios: hay varios problemas que quiero solventar. Por un lado falla al reconocer el simbolo, y por otro lado puede que no acepte combinaciones raras tipo “4+”, “+5”, “+”,”hfds+3”. La primera parte se puede solucionar dividiento el string en tres partes: operando, simbolo, operando. Para ello uso un boost::tokenizer y cambio la manera de enfocar las operaciones:
#pragma once
#include "string"
#include "sstream"
#include "boost/tokenizer.hpp"

class CText_calculator
{
private:
	int divide_string(const std::string& op,std::string& op1, std::string& simbolo, std::string& op2)
	{
		typedef boost::tokenizer > tokenizer;
		boost::char_separator sep("-+");
		tokenizer tokens(op,sep);
		tokenizer::iterator tok_iter = tokens.begin();
		op1 = *tok_iter++;
		if(tok_iter != tokens.end())
			op2 = *tok_iter;
		else
			return 1;
		simbolo = op.substr(op1.size(), 1);
		return 2;
	}
	int str_to_number(const std::string& str)
	{
		int result;
		std::stringstream ss(str);
		ss >> result;
		return result;
	}
public:
	int calculate(const std::string& op)
	{
		if(op.size() == 0)
			return 0;
		
		std::string op1, op2, symbol;
		int result = 0;
		if ( result = divide_string(op, op1, symbol, op2) == 1)
			return str_to_number(op1);
		if (symbol == "+")
			return str_to_number(op1) + str_to_number(op2);
		if (symbol == "-")
			return str_to_number(op1) - str_to_number(op2);
	}

	CText_calculator(void){}
	~CText_calculator(void){}
};
Añadir las dos operaciones que faltan es trivial. Solo hay que añadir los dos simbolos que faltan a la lista de separator char y añadir los if correspondientes. Añado primero los test:
TEST(text_calculator,005_10_mult_10_always_returns_100)
{
	CText_calculator tc;
	ASSERT_EQ(100, tc.calculate("10 * 10"));
}

TEST(text_calculator,006_15_divided_3_always_returns_5)
{
	CText_calculator tc;
	ASSERT_EQ(5, tc.calculate(" 15 / 3 "));
}
Ejecuto y aplico cambios. Recuerda que después de decir que el cambio era trivial, he escrito los tests y los he ejecutado. Parece paranoico pero es lo mejor por muchas razones. Primero por que la próxima vez que alguien le meta mano al código, ya están hechos los tests. Segundo por que un mal click puede introducir un simbolo incorrecto y luego ese error trivial convertirse en un error oscuro y difícil de encontrar dentro una aplicación mas grande El código final es este:
#pragma once
#include "string"
#include "sstream"
#include "boost/tokenizer.hpp"

class CText_calculator
{
private:
	int divide_string(const std::string& op,std::string& op1, std::string& simbolo, std::string& op2)
	{
		typedef boost::tokenizer > tokenizer;
		boost::char_separator sep("-+*/");
		tokenizer tokens(op,sep);
		tokenizer::iterator tok_iter = tokens.begin();
		op1 = *tok_iter++;
		if(tok_iter != tokens.end())
			op2 = *tok_iter;
		else
			return 1;
		simbolo = op.substr(op1.size(), 1);
		return 2;
	}
	int str_to_number(const std::string& str)
	{
		int result;
		std::stringstream ss(str);
		ss >> result;
		return result;
	}
public:
	int calculate(const std::string& op)
	{
		if(op.size() == 0)
			return 0;
		
		std::string op1, op2, symbol;
		int result = 0;
		if ( result = divide_string(op, op1, symbol, op2) == 1)
			return str_to_number(op1);
		if (symbol == "+")
			return str_to_number(op1) + str_to_number(op2);
		if (symbol == "-")
			return str_to_number(op1) - str_to_number(op2);
		if (symbol == "*")
			return str_to_number(op1) * str_to_number(op2);
		if (symbol == "/")
			return str_to_number(op1) / str_to_number(op2);
	}

	CText_calculator(void){}
	~CText_calculator(void){}
};
Todavia podriamos aplicar un refactor con todos esos “if” de la funcion publica, y para ello los test automáticos que hemos hecho nos ayudarian también. Si piensas que escribir los tests cases llevan mucho tiempo, piensa que en total no me ha llevado mas de 3 o cuatro minutos (son todo copy/paste). A cambio, la aplicación sale con un grado de madurez medio bueno, y eso que en realidad no he hecho todos los test que se me puedan ocurrir. Todavia quedarian por añadir casos algo más extremos como:
TEST(text_calculator,007_tests_with_wrong_values)
{
	CText_calculator tc;
	ASSERT_EQ(0, tc.calculate(" 1assadf / 3 "));
}
TEST(text_calculator,008_tests_with_wrong_values_2)
{
	CText_calculator tc;
	ASSERT_EQ(0, tc.calculate(" 15 / sadas3 "));
}
Y descubrir que este, por ejemplo, falla
TEST(text_calculator,009_tests_with_wrong_values_3)
{
	CText_calculator tc;
	ASSERT_EQ(0, tc.calculate(" 15  16/ 3 "));
}
Y deberia aplicar cambios, pero creo que a partir de ahi ya ves por donde va el tema. Espero que este articulo te haya demostrado como el TDD puede ayudarte a escribir mejor código a la vez que acelera el ritmo de produccion al evitar que los bugs se escondan en tu código durante demasiado tiempo. Si tienes alguna pregunta no dudes en postear.

jueves, 20 de octubre de 2011

Una entrada interesante sobre Boost.Serialization

Me ha interesado mucho este articulo en IBM.com sobre Boost.Serialization. Basicamente esta libreria te permite convertir un objeto en un chorro de bytes (y viceversa), permitiendote enviar objetos por la red o guardarlos en un archivo. Es ideal para ayudar a un desarrollador a crear partidas salvadas y cargarlas luego, o para crear partidas en red.

El articulo es en ingles, o sea, el idioma de la informatica y de internet (yo solo lo dejo ahi... para que lo pienses.... :) )

Espero que te guste.

jueves, 13 de octubre de 2011

Apuntes de Multithreading (II)


En este segundo capitulo pretendo mostrar como se crean threads. Un thread, como expliqué en el anterior artículo, es un objeto de la clase boost::thread, asi que al crearlo se llama al constructor.

Al crearlo, como parámetro de entrada le damos una función que es la que ejecutaremos en un thread separado.

void func1()
{
    //hacer algo aqui
}
int main()
{
    boost::thread t(func1);
    t.join();
}


Aunque tambien podemos usar functors para indicar al thread que tarea ejecutar.

class complexFunc2
{
    void operator()() const
    {
        //hacer algo complejo aqui.
    }  
};

int main()
{
    boost::thread t(complexFunc2);
    t.join();
}


Hay algo que es importante. El parametro que le pasamos a un thread entra por copia y no por referencia. Una vez finaliza el thread, el objeto que le hemos pasado por copia es destruido. Esta operacion no tiene ningún peligro excepto si entre tus datos miembro tienes punteros, y el destructor los intenta borrar, asi que cuidado.

Por ejemplo:

class complexFunc3
{
    int& number;
    complexFunc3(int& _number):number(_number){}
    void operator()() const
   {
     for(int i = 0; i < 10000; i++)
       printf("%d\n",number);
   }
};
int main()
{
    int myVar = 2;
    boost::thread t(complexFunc2(myVar));
}


Una vez acaba el main, el thread principal (nuestro programa principal siempre es un thread) acaba y libera recursos. En este caso myVar es destruida. Probablemente en una de las iteraciones del bucle, printf fallará porque myVar ha dejado de existir, y por tanto number es una referencia a un número que ya no existe, y fallará.

Para evitarlo deberiamos llamar al método join(), para que el main espere la finalización de thread antes de salir. El join deberia ser llamado si al final de una funcion o dentro de la excepcion. Esto es:

int main()
{  
    int myVar = 2;
    boost::thread t(complexFunc2(myVar));

    try{
        // Algunas operaciones que pueden gnerar excepcion.
    }
    catch()
    {
        t.join();
        throw;
    }
    t.join();
}


Nos puede ser útil tambien hacer lo contrario y es separar definitivamente el thread del principal. Para ello primero debemos comprobar que hay un thread para separar, o para juntar en caso de que vayamos a usar join. Para comprobarlo usamos t.joinable(), y si sale true es que podemos hacer un detach().

int main()
{  
    boost::thread t(func);
    if(t.joinable())
        t.detach();
}
Por ultimo, explico que pasar parámetros a un thread es trivial.
void func(int i, float f){}
int main()
{  
    boost::thread t(func,2,2.5f);
    t.join();
}


Pero no hay que olvidar que los parametros se copian y que al final de la ejecución son destruidos asi que hay que tener en cuenta que enviamos y que pasará cuando sean destruidos, o que pasará cuando la función que crea el thread finalice y destruya las funciones creadas alli y el thread siga en marcha.

Pues aqui llega el final de este post, aunque todavia me queda un largo camino con los threads.

lunes, 10 de octubre de 2011

Apuntes de Multithreading

Probablemente te vas a aburrir con esta entrada, pero no pretendia ser eso sino más bien una especie de apuntes por que estoy aprendiendo desde 0 un poco de multithreading en C++.  En realidad queria escribir algo de boost::thread, pero al final se ha juntado todo un poco...

En principio habria que saber que un thread es un proceso que se ejecuta paralelamente a la aplicacion. Desde el punto de vista de Boost (aunque dentro de poco será std::thread), un thread es una clase, que podemos crear cuando queramos. Si tenemos instalado boost como libreria global a todo el sistema, no necesitamos nada para compilarlo. El código seria este:

#include "iostream"
#include  "boost/thread.hpp"

void hola()
{
    std::cout<<"Hola mundos paralelos!!!\n";
}

int main()
{
    boost::thread t(hola);
    t.join();
}

Si esto te compila y ejecuta sin quejarse es que tienes bien instalado Boost. ¿Pero funciona realmente?
Vamos a probar esto:


#include "iostream"
#include  "boost/thread.hpp"

const unsigned int MAX = 1000;
void hola()
{
    for(unsigned int i = 0; i < MAX; ++i)
    {
    	std::cout << "Mensaje dentro de la funcion HOLA numero " << i << "\n";
    }
}
int main()
{
    boost::thread t(hola);
    for(unsigned int j = 0; j < MAX; ++j)
    {
    	std::cout << "Mensaje desde el main con numero " << j << "\n";
    }
    t.join();
}
Si redireccionas la salida a un archivo, por que son 2000 lineas, tendrás que las lineas no salen separadas. Puedes encontrar lineas como esta:
Mensaje desde el main con numero Mensaje dentro de la funcion HOLA numero 13
Mensaje desde el main con numero 1014
Los carácteres entran cuando pueden, aunque pise media frase en el camino del otro thread.

Y que hace este código? Pues primero creamos un objeto thread. Como parámetro del constructor, le pasamos la función que queremos ejecutar. Luego viene el bucle que escribe mensajes en el thread principal, aunque dentro del thread tambien se estan enviando mensajes. Una vez acaba el bucle principal, si no hubiera nada más, el programa principal acabaria y el thread se quedaria alli haciendo lo que sea que tiene que hacer.

Para decir al programa que cierre el thread antes de irse, llamamos a join() que es como pedirle al programa que espere en ese punto al thread antes de continuar, y despues continue.

Y asi acaba la primera entrada sobre threads.

sábado, 1 de octubre de 2011

Creando una fuente de objetos en Unity3D

Sigo con mis experimentos en Unity. Lo que estoy intentando hacer es una fuente de objetos, es decir, que sobre un punto se vayan instanciando objetos, que irán cayendo en el suelo y desapareciendo.

Creando el terreno:
En esta parte voy a crear una especide de caja donde irán cayendo los objetos. La caja tiene cuatro paredes bajas y un suelo. Para crear el suelo voy al menú, y busco GameObject | Create Other |  Cube. Para ir rápido lo voy a situar en el (0,0,0), y lo voy a poner de unos 20x20 con una altura (en unity, por defecto la altura siempre es la 'y') de 0,2.

Luego ajustamos las paredes una a una:
Las paredes son a ojo pero con uno de grosor y 21 de ancho (en unos casos será Z y en otros X) y con una altura de 3 debería valer.


En el momento de ejecutarlo lo vas a ver muy negro asi que pongo 3 - 4 luces. Una direccional, y el resto de tipo spot, que hacer un radio de luz. Puedes experimentar, si quieres y cambiar el color, intensidad, numero de luces, etc.


Creando el Prefab.
Ahora tenemos que ver el objeto que irá creandose en la fuente. Vamos a diseñar uno. Cuando tengamos lo que queremos, haremos un prefab, que es algo asi como un modelo o molde para poder crear copias idénticas.

En mi caso voy a crear un cubo de 0.5 de lado, al que llamaré falling_box (originalidad ante todo :) ). En principio lo pondo a 5 de altura. Para que se vea claro, le pongo un material cualquiera. Voy a Materials, y elijo uno. En mi caso Fire Add. El cubo, por sí solo no va a moverse. Necesito decirle al cubo que pesa y para eso le voy a añadir un componente de Rigid body. Con el objeto seleccionado voy a component, voy a Component | Physics | RigidBody y veremos que aparece un componente RigidBody en el inspector del objeto falling_box. Si le damos al play veremos que cae, aunque cae a plomo. Le vamos a cambiar el material del que esta hecho. Para eso, vamos a los assets y seleccionamos Physics Materials. Le ponemos Bouncy en el recudro del Box Collider, en el inspector. Ahora podemos darle al play otra vez y nuestro objeto rebotará alegremente por el suelo. 

Nota: Si rotamos un poco el cubo, unos 5-45 grados cada componente, el cubo no caerá plano y botará de manera realista.

Guardamos el proyecto (File | Save Project) y preparamos nuestros deditos de programador. Vamos a hacer algunos scripts. La idea es que al cabo de un tiempo los cubos vayan desapareciendo para que no se acumulen muchos. Para ello vamos a usar un Destroyer. Le diremos que se destruya a sí mismo al cabo de 5 segundos. 
Debemos ir al panel project, crear primero un folder llamado scripts y despues un script, que en mi caso se llamará AutoDestroyer y será en C#. Cuando se crea viene con 2 funciones sin codigo, update y start. Yo le añado el código a start para que quede asi:
public class AutoDestroy : MonoBehaviour {
    
    // Use this for initialization
    void Start() {
        Destroy(gameObject, 5);
    }
}
Si lo probamos, vemos que el objeto efectivamente cae y siempre se destruye al cabo de 5 segundos. Como ya tenemos el modelo que teniamos, vamos a enlatarlo. Para ello, vamos al panel project y creamos otro folder llamado prefabs. Despues en el mismo panel project hacemos click derecho y seleccionamos un prefab, al que llamaremos FalligBouncyCube. Al principio vemos que esta blanco, que quiere decir que no tiene nada. Ahora arrastramos nuestro FallingBox al prefab, y veremos que cambia de color. 

Para probar el prefab podemos arrastrar unas cuantas veces el prefab al hierarchy o a la escena, para ver como van apareciendo cubos. Si se superponen, podemos moverlos y situarlos donde queramos.

Creando la fuente de los cubos.
La fuente de los cubos es simplemente un punto en el espacio. Se pueden crear GameObjects vacios. Lo único que tienen es una posición + rotación + escala, o sea una transformación. Lo situamos en 0,5,0. Le añadimos un script que cada segundo lance un cubo. El script seria este:
public GameObject thePrefab;
private float m_timeCounter;
private int m_objectCounter;

// Use this for initialization
void Start () {
	m_timeCounter = 0.0f;
	m_objectCounter = 0;
}

// Update is called once per frame
void Update () {
	
	m_timeCounter += Time.deltaTime;
	if(m_timeCounter > 1 && m_objectCounter < 300)
	{
		m_timeCounter = 0;
		Instantiate(thePrefab,transform.position, transform.rotation);	
		m_objectCounter++;
	}
}
Por partes. El start es un constructor. Alli inicializamos objetos. Si te fijas tenemos 3 miembros, dos privados y uno publico. El public es visible desde fuera, pero que quiere decir esto? Al arrastrar el script al objeto vacio vemos que aparece esto:
Asi que si le arrastramos el objeto FallingBouncyCube sera exactamente eso lo que cree. Cada cuanto lo creará? Cada segundo. Time.deltaTime guarda el tiempo que pasa entre cada frame, con lo que sumando tiempos conseguimos un reloj rudimentario. Para limitar el número de objetos, contamos en m_objectCounter y como maximo serán 300. Lo probamos y vemos que cada segundo cae un cubo, que tarda 5 segundos en desaparecer. Asi que solo veremos 5 cubos en pantalla.

Pero funciona!!! En un post futuro, flexibilizare todo esto que he creado para que sea mas cómodo configurarlo. Si tienes alguna duda, escribe un post!!!


martes, 27 de septiembre de 2011

Boost filesystem

Una de las librerias que siempre vienen bien conocer en boost es la filesystem. Parece una tonteria pero se pueden llegar a gastar unas cuantas horas programando y debuggando un sistema de ficheros. Si ademas es multiplataforma todavía más. Por que a los separadores de ficheros, que segun el sistema puede ser "/" o "\", se suma que en sistemas windows existen las "unidades" (C: E: D:),  que en linux existen los enlaces soft y hard...

Además de estas dificultades, que plagan nuestro código de #ifdef win32 #elseif.... , otros problemas que muchas veces nos hace acabar recurriendo al socorrido system(cmd). Con boost tenemos un codigo unificado que no desordea nuestro codigo y que nos permite interactuar con el sistema de ficheros. Podemos añadirlo con la cabecera:

#include "boost/filesystem.hpp"

Lo primero que tenemos que conocer es la clase path. La declaramos asi:


boost::filesystem::path ruta("myDir");


Otra cosa importante es que el operator/ esta sobrecargado y hace la concatenacion de directorios. Junto con la ruta declarada antes, podriamos hacer:
boost::filesystem::path ruta("myDir");
boost::filesystem::path root("myRootDir");
boost::filesystem::path completeRoot = root / ruta;
// podriamos hacer lo mismo pero ahorrando una variable con root /= ruta

Dentro de la libreria podemos encontrar algunas funciones muy útiles para borrar y crear directorios y archivos:
boost::filesystem::create_directory("dir");
boost::filesystem::remove_all("file");

E incluso para saber si existe un archivo, conocer si es un directorio, un archivo o un link
boost::filesystem::exists("file");
if(boost::filesystem::is_directory("file"))
{}

Para acabar, los iteradores nos permiten recorrer los contenidos de un determinado directorio:
boost::filesystem::directory_iterator end_iter;
boost::filesystem::directory_iterator dir_iter(directory);
for(dir_iter; dir_iter != end_iter; ++dir_iter)
{

}


En zeleste2D, esta es la funcion para crear recursivamente una ruta que no existe:
//TODO: Would this method be more general and live outside this class??
bool pathCreator( boost::filesystem::path& path_to_create )
{
 if (!fs::exists(path_to_create))
 {
     pathCreator(path_to_create.parent_path());
 }
//if not create the directory
fs::create_directory(path_to_create);
return true;

Funciones, code forwarding y slicing

Está claro que cuando declaramos una función estamos estableciendo como nos comunicaremos con el código cliente. Pero todos conocemos que en c++ existen 3 maneras diferentes de pasar parámetros: por valor, por parámetros y por referencia. Como deberíamos diseñar pues la interface de nuestras funciones? Segun la guia de estilo de google deberíamos diseñar las funciones poniendo las variables de entrada y salida como punteros y las variables de entrada como referencias constantes. Algo asi:


type1& funct(const type2& ref, type3* point){}



Salvando memoria
La primera ventaja de las referencias en las funciones y métodos va por triplicado. Por un lado es transparente para el usuario, puesto que podemos insertar las variables sin semántica de punteros y manejarlas dentro de la función de la misma forma. Además, consumimos menos memoria, puesto que solo copiamos la referencia del parametro y no copiamos el objeto. Para darnos cuenta de cuando copiamos un objeto, una manera muy buenas es usar una macro como esta:


// A macro to disallow the copy constructor and operator= functions
// This should be used in the private: declarations for a class
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
  TypeName(const TypeName&);               \
  void operator=(const TypeName&)




Después podemos declarar nuestras clases asi:


class Foo {
 public:
  Foo(int f);
  ~Foo();

 private:
  DISALLOW_COPY_AND_ASSIGN(Foo);
};




Gracias a esto, nos aseguramos que el compilador nos prohiba copiar un objeto y pare la compilación. Es una buena costumbre la de usar el compilador para protegernos de errores.

Code forwarding
La segunda ventaja viene al diseñar clases , con el code forwarding. Cuando la interface de una clase solo declara punteros a otra clase, no necesitamos la cabecera para definirlos. Esto es: si tenemos una clase asi


class Forwarded;

class Declared{

    Forwarded* m_for;

    void fund(Forwarded* f);

};



Esta clase compilaria perfectamente, puesto que Forwarded son punteros asi que el compilador no necesita conocer ningun detalle más de Forwarded para compilar. Lo unico que necesitamos es declarar la clase de manera adelantada. Es una manera de decirle al compilador: "existe una clase llamada Forwarded. Tu compila, que luego de doy mas detalles". Pero cuando le damos los detalles? Pues en el fichero de codigo, en el .cpp, es donde se hace el include.

Y que ganamos con esto? La mayoria del tiempo que tarda la compilación es en operaciones recursivas de inclusion de codigo, o sea, en parseo. Cada vez que variamos una parte del codigo de un fichero afecta a todas las cabeceras incluidas de manera recursiva en esa unidad de compilacion. Declarando el include en el fichero .cpp retiramos esta cabecera del circuito y hacemos que la compilación sea mucho mas rápida

Slicing (rebanamiento)
La tercera ventaja es que evitamos el slicing. El slicing es un problema de c++ al copiar en una variable de tipo A, una variable de tipo B que deriva A. Si tenemos las clases


class A{

public:

    int t1;

};

class B: public A{

public:

    int t2;

};


Si hacemos esto:


B b;

b.t1 = 2;

b.t2 = 3;

A a = b;

// t2 no ha sido copiado.

B b2 = a;

assert(b2.t2 == b.t2); // esto fallará


Que ha pasado? Pues que en la copia entre clases, A no tiene un miembro t2, asi que no lo copia. Cuando volvemos a copiar A en B, ese miembro ya no esta en A y por tanto es indefinido en B. Este caso es claro en el codigo anterior pero se puede hacer más dificil de ver en el paso de parametros en una funcion que acepte parametros polimorficos. Al pasar la referencia, ayudamos a prevenir esta perdida de información. Por ejemplo


B* b = new B;

b->t1 = 2;

b->t2 = 3;

A* a = b;

B* b2 = a;

assert(b2->t2 == b->t2); //OK

lunes, 26 de septiembre de 2011

Boost Hash

Esta entrada va a ser muy corta, o eso espero... Boost::hash es una libreria que nos facilita el calculo del hash de cualquier entrada. Más que facilitarlo lo soluciona completamente :)

Este seria un caso muy directo:


#include "iostream"
#include "boost/functional/hash.hpp"
int main()
{
    boost::hash string_hash;
    size_t myHash = string_hash("Hola mundo");
    std::cout << "Mi hash es " << myHash << std::endl;
    return EXIT_SUCCESS;   
}

Tambien se puede lo deberiamos usar para indexar maps. Imagina que tenemos una funcion que recibe un directorio y un objeto de una clase T, y que eso lo guardamos en un std::map. Los directorios son del tipo "c:\archivos de programas\bla bla bla\jejeje\archivo". Si te fijas, cuando se empieza a comparar la función,  los 15 primeros carácteres son siempre iguales, asi que podemos perder ciclos comparando. Lo que podemos hacer es, al insertar el objeto T, calcular el hash del directorio y devolver el hash como ID. Asi nuestros accesos posteriores seran rapidisimos.

std::size_t insert( const std::string& dir, T& objeto)
{
    std::size_t hash = string_hash(dir);
    myMap[hash] = objeto;
    return hash;
}

Ahora podriamos recuperar el objeto facilmente con el ID (no controlamos los errores).
T& get(const std::size_t id)
{
   return myMap[id];
}
Nota: He incluido las cabeceras como #include "iostream" por un tema del plugin de blogger, que me formatea mal el código, pero lo puedes poner como quieras.

sábado, 24 de septiembre de 2011

Boost. Ponle el turbo a C++

Encuentro que hay mucha gente que desconoce Boost Supongo que también hay mucha gente que desconoce que C++ esta a punto de cambiar de standard, y que muchas de las funcionalidades nuevas están en Boost. De ahi que muchas de las sentencias como:
boost::Thread t1;
Pasarán a ser:
std::Thread t1;
Es decir, parte del estandar. Boost ademas ahonda en la idea de algunas tecnologias que implementa el nuevo estandar, como auto_ptr que boost completa con los scoped_ptr, shared_ptr, etc.
Por otro lado, boost llena agujeros que tradicioanlmente ha tenido C/C++. Por ejemplo, C++ no tiene una libreria unificada para tranajar con el sistema de ficheros. No hay una función que nos devuelva, por ejemplo, si un fichero existe y cuanto mide, y tenemos que recurrir a librerias de terceros. Tampoco tiene una libreria de fechas unificada.
Y eso que significa? Pues que cualquier programador de c++ deberia tener instaladas las librerias boost en su ordenador, y aprender a usarlas para no tener que reinventar la rueda constantemente.

Boost para novatos:
Pues de novato a novato te voy a decir una cosa. Boost no es dificil de instalar. De hecho es muy fácil:
Las bajamos desde esta pagina. En la sección de packaged downloads nos bajamos la última versión. Lo mejor es bajar el que esta comprimido en 7z por que es el mas pequeño en windows. En linux sirve el que quieras que sea gz. Ahora lo podemos instalar. En Window necesitamos 4 sencillos pasos:

1. Crear un destino
Creamos una carpeta en nuestro ordenador donde queramos instalar las librerias de manera definitiva. Por ejemplo en c:\dev-libs\boost. (lo mejor es que la ruta no tenga espacios en blanco, por si acaso)

2. Ir al constructor de boost
Al acabar de descomprimir tendremos una carpeta de nombre boost_version (puede ser boost_1_47_0 por ejemplo). Vamos dentro de esta carperta a .\tools\build\v2. Abrimos una consola y escribimos los siguientes comandos estando en esa ruta:

bootstrap.bat
.\b2

Esperamos a que acabe todo y entonces tendremos una herramienta llamada bjam. Ahora vamos a la raiz de boost (c:\dev-libs\boost en nuestro caso) y escribimos .\tools\build\v2\bjam y entonces empieza la construccion de boost de verdad.


3. Esperar
Ir a por un café. Si estas en el curro ves a hablar con esa de marketing tan guapa... esa que tu y yo sabemos. La compilación se puede alargar un ratito dependiendo de la máquina que tengas.


4. Añadir la ruta al PATH
Ahora solo te queda añadir lo que iba en prefix + bin, en mi caso c:\dev-libs\boost\1.47\bin al path. Aunque tambien podemos instalarlo directamente en Visual Studio para no enredar con el PATH. Para ello vamos a Herramientas -> Opciones -> Proyectos y soluciones -> Directorios de VC++
Alli añadimos "c:\dev-libs\boost\1.47\" en "Archivos de inclusion" y "c:\dev-libs\boost\1.47\stage\lib" en "Archivos de biblioteca". Asi boost estará disponible para cualquier proyecto.
Y con eso quedaria instalado. Ahora, sin ninguna confuguracion adicional del proyecto deberiamos poder compilar algo como esto:
#include 
#include 
#include 

int main()
{
    std::string line;
    boost::regex pat( "^Subject: (Re: |Aw: )*(.*)" );

    while (std::cin)
    {
        std::getline(std::cin, line);
        boost::smatch matches;
        if (boost::regex_match(line, matches, pat))
            std::cout << matches[2] << std::endl;
    }
}
Y con eso ya tendriamos boost instalado. En general ni es tan largo ni complicado como mucha gente piensa. Espero que esto te anime a empezar. En los proximos dias escribire algunas entradas sobre librerias de boost que me parecen especialmente utiles.

Pasitos con Unity

Hace unos días me baje Unity3D para trastear un poco y la verdad es que parece un producto muy bien hecho. Lo primero que sorprende es su sencillez de ideas. Tenemos la ventana de diseño, donde vemos la escena que hemos montado, la jerarquia, que es donde montamos la escena a base de interrelacionar assets, el panel de proyecto, que es donde nuestros assets disponibles estan listos para usarse y el panel de inspeccion.

Casi todo pasa con sencillez. Queremos una luz? Buscamos en el panel de proyecto por los tipos de luces disponibles, elegimos una, la arrastramos al panel de jerarquia y en el inspector podemos cambiarle las propiedades. Casi todos los elementos estan pensados asi, con lo que ganamos en sencillez.

Unitiy no sorprende por herrmamientas 3D, o de retoque de imagen o de sonido, sino que se limitan a aconsejarte que busques alguna herramienta de verdad como Maya o Photoshop. Pero Unity3D provee metodos para recoger los productos de estas herramientas y cargarlos como assets. Tambien viene con el editor mono, para javascript o c#. Y de momento eso es lo que he visto hasta ahora. Ya ire poniendo mas entradas donde explique como me va con Unity3D

jueves, 22 de septiembre de 2011

Probando tu codigo en C++ con gtest (II)


El porque de las pruebas unitarias


En la entrada anterior planteaba la necesidad de hacer test unitarios, ademas de explicar como montar la librería  compilarla y usarla. Pero quizás hay una pregunta que no respondo y es: para que? Para que una librería cuando podemos hacer programas de ejemplo?
En esta segunda entrada quiero hablar desde un punto de vista diferente y explicar que se busca con las pruebas unitarias y que estrategia tomar para sacarle partido a estas:

Imagina que estas programando y usas las STL. Al ejecutar, aparece un error muy raro. Al debugar, la excepción salta en medio del código de una de las clases que implementan std::vector. Le echaras la culpa a las STL? Las mirarás en profundidad? No. Seguro que no. Tendrás la seguridad de que lo que falla es tu código, por que sabes que las STL han sido probadas una y otra vez (y aun y así todavía tienen errores, aunque son difíciles de encontrar). Esa tranquilidad agiliza el desarrollo puesto que en caso de error siempre miramos el último código. Esa es una de las fortalezas de la reutilización de código.

Cuando pruebas su código, muchas veces haces algunas funciones de prueba pero, lo haces de una manera estructurada? Por ejemplo, esta función:

int dividir(const int a, const int b)
{
   return (a/b);
}

Como la probarías?
En principio no haríamos nada raro: un par de llamadas y ver el resultado. Con google test seria así

TEST(funcionDividirTest, dividir)
{
    EXPECT_EQ(dividir(5,2),7);
    EXPECT_EQ(dividir(5,-5),0);
}

No hay nada que hacer. Al final siempre hay bugs. En este caso, por ejemplo, no se contempla la division por cero. Si has hecho bien tu trabajo de pruebas, arreglarás el bug, y añadiras una prueba más a tu set de pruebas, y te asegurarás de que en cada compilación se ejecuten todas las pruebas. La ganancia principal aquí con las pruebas unitarias es que podemos probar nuestro código cada vez que compilamos una nueva version. En codigo más complejo, cuando probamos funciones de más alto nivel, nos permitirá descubrir cuando alguien ha metido la pata.


La vista puesta en la calidad

Resolver bugs es aburrido y una perdida de tiempo. Lo mejor es no fallar al programar. Como es casi imposible, las pruebas unitarias hacen que una vez escritas las pruebas por alli ya no fallará el programa (y si falla sera algo muy localizado). No harías ningun sacrificio por esa buena causa? Pues intenta que el código sea probable. Para hacerlo, intenta que tus funciones y métodos devuelvan algo. Si la función no debería devolver nada, pues que devuelva 0 en caso de éxito y algún valor de error en caso contrario (debidamente documentado). Evidentemente, cambiar el diseño para que sea fácilmente probable puede ser costoso pero creo que se sale ganando con creces.

Se consistente en el manejo de errores. Devuelve un código de error o haz saltar una excepción, pero no mezcles estrategias en el código.

Lleva un control de lo que has probado, pero también de lo que no has probado. Es casi más importante saber que código esta en el aire.

Desacopla tu código, por que si no las inicializaciones son pesadas y penosas. Cada subsistema debería poderse compilar por separado (siempre que sea posible). Desacoplar el código significa que cada subsistema habla con los otros subsistema a través de unas interfaces muy determinadas. Hay que evitar situaciones donde cada clases de un subsistema tiene que conocer muchas cosas de otro subsistema



Test driven development

Pero se puede hacer algo más?
Pués si. Imagina que un jefe de proyecto, manager o lo que sea te da esto:

int factorial(const int n)
{
    return 0;
}

Y además esto:
TEST(funcFactorial, aceptacion)
{
    EXPECT_EQ(factorial(0), 0);
    EXPECT_EQ(factorial(1), 1);
    EXPECT_EQ(factorial(2), 2);
    EXPECT_EQ(factorial(5), 120);
    int n = 20;
    EXPECT_EQ(factorial(n), factorial(n -1)*n);
}

Digamos que con la interface de la función yo puedo compilar, aunque siempre me devolverá 0, pero yo puedo ir haciendo otro trabajo. Tu trabajo seria programar la funcion de manera que pase el test unitario. Programala como quieras mientras no cambies la signatura de la funcion y siempre que el resultado del test sea verde.

Esta estrategia, de crear lo test antes de el codigo que bajo test, se llama test driven development. Este tipo de estrategia, aunque parezca lenta, puede llegar a reducir el tiempo de desarrollo y aumenta la calidad del codigo final, ademas de reducir el tiempo de desarrollo al haber menos fallos.

lunes, 20 de septiembre de 2010

Probando tu codigo en C++ con gtest

La necesitadad de probar las cosas
En las ultimas semanas me ha entrado un ataque de creatividad y he escrito bastante código para mi motor gráfico en eterna creación. La verdad es que los casos directos funcionan pero van apareciendo errores y eso te paraliza bastante porque tienes que pararte y analizar lo que has hecho y alguna que otra vez rediseñar y cambiar un monton de cosas.
Para evitar esto, ultimamente he estado buscando algunas herramientas de test unitarios para C++ y he encontrado una que me ha gustado bastante. Multiplataforma, simple y rapida, sin muchas florituras pero parece que bastante madura. Y con el sello de google. Sí, es google test. En este articulo voy a describir como preparar tu entorno Visual Studio con google test para empezar a probar tu código.
Compilando gtest desde las fuentes
Lo primero que vamos a hacer es bajar una copia del código fuente. Podemos obtener el código aqui. Yo bajo la 1.5.0. Ahora solo hay que descomprimir en un directorio de windows. Una vez descomprimido podemos ver que hay un subdirectorio llamado msvc. Aqui se guardan los proyectos para compilar las librerias de gtest. Veras que hay dos soluciones de proyecto (lo que antes eran los workspace de VC++): gtest.sln y gtest_md.sln. La diferencia entre uno y otro la explicaré más adelante. Nos quedaremos con el primero. Si tenemos Visual Studio 2005 la solución se abrirá directamente. Si tenemos Visual Studio 2008/2010 entonces se abrirá el convertidor de soluciones.

Una vez abierto, veremos que tenemos 4 proyectos incluidos en la solución.

No nos preocuparemos demasiado por que solo queremos generar las librerias. Hacemos click derecho en la solución y seleccionamos generar solución.
En principio, y si no pasa nada raro, deberia acabar sin errores ni advertencias, habiendo compilado los 4 proyectos. Si te fijas, dentro del directorio msvc, ahora existe una carpeta llamada gtest. Dentro de gtest, se ha creado otra llamada Debug. Y dentro, se han creado las librerias y ejecutables resultantes de la compilación. Veras que tienes un archivo llamado gtest_maind.lib y otro llamado gtestd.lib. Estos son las librerias estaticas que necesitamos para nuestros tests.

Ahora vamos a compilarlas en modo Release. Vamos a Visual Studio y arriba, en la barra de herramientas estandar, cambiamos la configuración de Debug a Release. Ahora, como antes, hacemos click derecho en la solución y generamos la solución. Como antes vamos a msvc->gtest, pero ahora veremos dos directorios. Uno de ellos se llama Release. Tambien contiene dos ficheros .lib.

Instalar gtest en nuestra máquina

Dentro del directorio de gtest, existe un directorio llamado include. Ademas, ya hemos explicado donde quedan los .lib tanto de degub como de release. Ahora podemos hacer dos cosas. O le explicamos al IDE donde encontrar estos dos directorios o le decimos a cada proyecto donde estan. En general soy partidario de lo segundo, pero en este caso lo voy a instalar de manera global puesto que esta es una libreria de uso muy general y usable en casi cualquier proyecto, como boost, por ejemplo.

Asi que en Visual Studio voy a Herramientas, opciones... y alli voy a proyectos y soluciones y selecciono Directorios VC++. Alli añado el directorio Debug y Release resultante de la compilación anterior en el apartado de archivos de biblioteca, y añado el directorio include dentro de archivos de inclusion:
Le doy a aceptar y ya tenemos "instalado" gtest en nuestro IDE

El primer proyecto de tests de unidad

Lo unico que necesitamos hacer para crear un test minimo de gtest es lo siguiente. Creamos un nuevo proyecto, en general dentro de la solución donde estemos creando nuestro proyecto principal y le ponemos un nombre que parezca importante (por nuestro ego y todo eso...), como unit_Tests. El proyecto, lo haremos vacio y de win32 console.

Ahora hacemos click derecho en el proyecto y vamos vinculador --> entrada -->dependencias adicionales y alli añadimos, gtestd.lib y gtest_maind.lib si estamos en Debug, y lo mismo pero sin la 'd' si estamos en release.

Nota!!
Si no hubieramos configurado nuestro IDE para saber donde estan estos archivos necesitariamos decirselo añadiendo los directorios de los .lib en vinculador-->general-->directorios de bibliotecas adicionales.

Ademas deberiamos instruir al proyecto sobre donde se encuentran los directorios de include, poniendoles su situacion en C/C++ --> directorios de inclusion adicionales.

Y ahora ya tenemos preparado nuestro proyecto para ejecutar test. Vamos a crear un archivo unit_tests.cpp (por ejemplo), con el siguiente código:


#include <gtest/gtest.h>

TEST(UnitTestSample,TestOne){
EXPECT_EQ(1,1);
}

Te recomiendo que ejecutes con CTRL-F5 para que la ejecución se pare antes de cerrar la ventana. Deberias ver esto:
Y eso es todo!! Con esto ya puedes probar de manera automatica que 1 es igual a 1, y muchas otras cosas más. Ahora importa tu código y demuestra que es robusto como una roca!!!

A continuación algunas explicaciones que he dejado para el final para no desviarme del tema principal.

Nota1: Te habrás dado cuenta de que el codigo no tiene función main. Esto es por que al añadir gtest_main(d).lib, ya añadimos un main que ejecuta todos nuestros test. Puedes consultar en la documentación del proyecto como generar tu propio main. Pero te recomiendo que lo uses asi, puesto que el código más seguro es el que no se escribe.


Nota2: Antes he explicado que hay que elegir la solución gtest y no la gtest_md. Bueno, en realidad lo importante es que si eliges gtest_md, entonces en la configuración de tu proyecto debes elegir en C/C++ --> generacion de código --> biblioteca en tiempo de ejecucion la opcion depuracion multiproceso si es en Debug y mutiproceso si estamos en Release. Si por el contrario elegimos gtest, entonces seleccionaremos DLL multiproceso.

miércoles, 1 de septiembre de 2010

Comprobar "Endianess"

Pequeño truquito para comprobar como se ordenan los bytes en la memoria de la maquina:

int i = 1;
char c = *(char *) &i;

if (c) {
cout << "Little endian" << endl;
} else {
cout << "Big endian" << endl;
}


Encontrado via:

De std::wstring a std::string

Una manera practica para pasar de std::wstring a std::string y viceversa:


#include <string>
#include <algorithm>

// Prototype for conversion functions
std::wstring StringToWString(const std::string& s);
std::string WStringToString(const std::wstring& s);

std::wstring StringToWString(const std::string& s)
{
std::wstring temp(s.length(),L' ');
std::copy(s.begin(), s.end(), temp.begin());
return temp;
}


std::string WStringToString(const std::wstring& s)
{
std::string temp(s.length(), ' ');
std::copy(s.begin(), s.end(), temp.begin());
return temp;
}


Encontrado via: http://www.codeguru.com/forum/showthread.php?t=193852

viernes, 29 de enero de 2010

Apuntes de optimizacion de C++

Algunos detalles sobre optimizacion de código de C++ que he ido encrontrando por ahi:

1. Inicializar clases
Inicializar las properties de las clases. La inicialización de las clases, se hacen despues de crear las clases contenidas. Es decir, si tenemos una clase A que contiene una clase B y una C, en el momento que creamos la clase A, antes de considerarse creada, se han creado las clases B y C. Asi, si creamos la clase player : tenemos que primero se crea los strings m_Name y m_Profesion y despues entramos en el codigo del constructor. Por eso este código:

class Player
{
public:
Player(const std::string &name)
{
m_Nombre = name;
}
private:
std::string m_Nombre;
std::string m_Profesion;
};

es mas lento que este

class Player
{
public:
Player(const std::string &name)
:m_Nombre(name)
{
}
private:
std::string m_Nombre;
std::string m_Profesion;
};

Porque en el primer caso, primero inicializamos m_Nombre a su valor por defecto y despues a 'name'

2. Crear y definir en la misma linea:

En vez de usar

int nPlayer;
nPlayer = 10;

Es mejor usar

int nPlayer = 10;

Por lo mismo que antes.

3. Mejor preincremento que post incremento:
Es mejor ++i que i++;

4. Sumas de variables:
Casi siempre es mejor

value3 += value2;

que

value3 = value2 + value1;


5. Crea las variables cuando toque:
No crees la variable al principio de la funcion, asi:

bool foo(CVehicle* veh)
{

CPlayer tempPlayer;
if (veh == NULL)
return false;

//.....
}

En este codigo, si veh es nulo, para que crear tempPlayer? Ni no se va a usar....

martes, 19 de enero de 2010

Interfaces graficas con QT

Últimamente, ademas de haber estado viciado al assassin's creed 2, me he dedicado a echarle un vistazo a QT. Estas librerias, hechas por trolltech hasta que nokia las compro, son librerías para hacer interfaces gráficas de usuario (GUIs). Son multiplataforma, echas en C++, LGPL y muy robustas y rapidas. Es decir, un verdadero paraiso. Si ademas estas trabajando en Visual Studio, no hay problema: te las compilas, instalas el Visual Studio Add-in y ya puedes compilar tus programas con tus GUIs desde VS. Hacerlo es muy facil. Te lo resumo en estos sencillos pasos:
1.- Bajarse la version del framework para windows de QT (actualmente la 4.6)
2.- Bajarse el visual studio add-in
3.- Instalar las librerias de QT en un directorio SIN ESPACIOS (por ejemplo C:\QT\2009.06)
4.- Crear una variable de entorno que apunte a tu directorio de instalacion llamada QTDIR
5.- Abrir la consola para visual studio o abrir la linea de comandos y llamar a vcvars32.bat. LA consola de visual studio se puede abrir desde el menu inicio, dentro del grupo de visual studio, o desde dentro del visual studio, en Herramientas -> Visual Studio 2008 Command Prompt
6.- Usar la consola que hemos abierto para ir al directorio de instalacion de QT
7.- Escribir C:\Qt\2009.06\configure -platform win32-msvc2008 (si falla la compilación, hay mucha gente que desconecta el Webkit añadiendo -no-WebKit)
8.- Escribir nmake
9.- Esperar....
10.-Esperar un rato mas....
11.- Segun la máquina que tengas, en unas 2 horas (que tambien pueden ser 5), se acabará compilando el codigo.
12 .- Instalar el visual studio add-in
13.- Hacer un proyecto de prueba. Para hacer la prueba crea un nuevo proyecto de QT en Visual Studio. Escribe este código en el main.cpp

#include
#include

int main(int argc, char *argv[])
{
QApplication app(argc, argv);

QPushButton hello("Hello world!");

hello.show();
return app.exec();
}

Si te funciona a la primera, felicidades. Yo he tenido que consultar algunos foros por que no acababa de funcionar. Una de las cosas que pasaban es que el manifest tool de Visual Studio daba problemas. Lo mejor es que si falla la compilación, ves al antivirus y excluye el mt.exe de la monitorizacion continua, y tambien la ruta del QT. Parece que eso hace que desaparezca ese tipo de error. Otra es que tuve que NO instalar el webkit, por que fallaba la compilación.

Tienes un montón de documentación sobre QT. Especialmente te recomiendo los tutoriales. Todavia tengo que mirar como cuadra el QT designer con el código generado en Visual Studio.

martes, 24 de noviembre de 2009

Un sistema de Log sencillo y flexible

Está bastante claro que es necesario guardar lo que hace el código por dentro. Un buen log puede guardar lo que haga tu código y eso es bastante importante. También debería ser importante el poder invocarlo de manera sencilla, es decir, que no fuera necesario meter toda una suerte de instrucciones para incializarlo en cada archivo fuente en el que necesites guardar mensajes. Y además, se debería poder poner los mensajes en archivos separados o descartarlos para ganar performance.

Hasta ahora tiraba con diferentes códigos que encontraba en la web. Pero casi todos me resultaban algo complicados, o demasiado pobres en cuanto a prestaciones. Ademas yo estaba acostumbrado a Log4Java, pero el port a C++ se me hacia raro, así que siguiendo un modelo parecido me decidí a hacer el mio propio. En principio, los requisitos que quería cumplir eran los siguientes.
  • Los mensajes debían ir a todos a la misma estructura de memoria. No quería buscar donde había puesto un mensaje.
  • Debía ordenar los mensajes por grupos, para asi poder recordar mensajes de un sub sistema separados de otros.
  • Debía poder filtrarse por nivel de importancia.
  • Debía ser portable (en la medida de lo posible)

No miré que fuera thread safe, aunque en un futuro quizás me lio con programación multihilo, por que de momento no tengo muy estudiado el tema, pero por lo demás si que cumplí con las expectativas. Aplique un patron observer-observable, de manera que podía hacer una clase que aceptara todos los mensajes, y por otro lado, aquellas clases que quieran procesar los mensajes, se tienen que añadir como listeners(observer). Cada listener tiene la posibilidad de procesar los mensajes como quiera, es decir, no hay problema para que los mensajes vayan a la consola, a un archivo, a una base de datos o simplemente ser ignorados. Simplemente teniamos que implementar una clase abstracta para que procese el mensaje entrante y lo mande donde sea necesario.

La clase que procesa los mensajes se crea en una sola linea (es un singleton), y sin configuración adicional ya acepta mensajes, con lo que al principio de una clase y con sola una linea, ya puedo añadir mensajes a la cola de mensajes.

// inicializacion del sistema de logs
tools::log::CGlobalLog *theLog = tools::log::CGlobalLog::getInstance();


También es muy fácil añadir grupos nuevos para mensajes de sistemas independientes. Se pueden entender los grupos como filtros, o como asociar un determinado mensaje a un nombre o sistema. Solo hay que añadir un grupo de log.

//el primer grupo lo añadimos explicitamente
theLog->addLoggerGroup(lgroup1);

theLog->addListener(&w2,lgroup2); //este segundo grupo se añade de manera implicita, juto al añadir el listener

y a partir de ahí solo hay que enviar los mensajes a ese grupo de log. En caso de que queramos ganar en performance, simplemente debemos 'aumentar' el nivel minimo de los mensajes. Por ejemplo, cuando estamos depurando podemos poner como nivel minimo de mensaje "debug" que es el nivel minimo. Esto hace que se acepten todos los mensajes. En cambio, cuando ya tenemos el producto final podemos decir que solo acepte los que tengan un nivel igual o superior a 'warning'.

//decimos que el nivel minimo para que un mensaje se guarde es WARNING
theLog->setMinimumLogLevel(tools::log::LOGLEVEL_WARNING);

Le dejo el código para quien quiera usarlo, junto con un main.cpp de prueba. Simplemente, te pido que si encuentras algún error me avises.

Descargar código(5.35KB)