c++ – Preprocesador – Duda existencial – c++ c git

Pregunta:


realmente tengo una duda existencia, y a medida que avanzo me hace mas ruido y realmente no sé si estoy haciendo las cosas bien. Tengo un software propio, que he desarrollado hace unos meses atras…va bastante bien en su finalidad, pero resulta que me han pedido otro que tiene la funcionalidad del anterior pero que agrega funcionalidades adicionales…osea, el primero se basa en el segundo.
Lo que a mí se me ocurrió, es sobre el juego de fuentes, definir una constante a nivel del proyecto y agregar sentencias del preprocesador…en principio se me ocurrió que era lo mejor…de esa manera solo cambiaría en lugares claves solo cuando necesito clases nuevas de la nueva funcionalidad…PERO a medida que avanzo veo que se complica y el código se vuelve in-mantenible. Muestro partes para que vean que me esta sucediendo.

#include "enginegraph.h"
#include "trackfarmgraph.h"
#ifdef __CORTE_SECCION__
#include "multiworkerdpathgraph.h"
#else
#include "workedpathgraph.h"
#endif
#include "pointsfarmgraph.h"

…. en otras partes del proyecto …

pointsGraph = NULL;
#ifndef __CORTE_SECCION__
    worker = NULL;
#else
    multiWorker = NULL; 
#endif
engine = NULL;
dlg = NULL;

…. en otras partes del proyecto …

#ifndef __CORTE_SECCION__
if (worker)
{
    disconnect(worker);
    delete worker;
    worker = NULL;
}
#else
if (multiWorker)
{
    disconnect(multiWorker);
    delete multiWorker;
    multiWorker = NULL;
}
#endif

if (track)
{
    disconnect(track);
    delete track;
    track = NULL;
}

Con esto voy notando que el código se torna ilegible y con el tiempo lo será mas.
La ventaja que encuentro es que si aparecen bugs en la parte comun, se corrigen y ambos software quedan OK…pero el costo de ilegibilidad y mantenimiento creo que crece exponencialmente.
De que otra forma se puede hacer esto?. GRACIAS

Preguntado por: Emiliano Torres

Neoniet

Te voy a poner un ejemplo sencillo.

Iniciamos un repositorio

git init

Añadimos los archivos iniciales del programa

git add main.cpp Clase1.cpp Clase1.hpp

git commit -m “Programa inicial”

Un cliente nos pide una cosa muy especial que probablemente no le valdrá al resto. El cliente tiquismiquis!!
Pues nos creamos una rama

git checkout -b clientetiquismiquis

Añadimos los nuevos archivos y las modificaciones de los antiguos

git add *

git commit -m “Versión para cliente tiquismiquis lista”

Ahora saltamos a nuestra versión principal para seguir mejorando el programa

git checkout master

Añadimos las mejoras a la rama principal

git add *

git commit -m “Mejoras añadidas”

Y ahora queremos mejorar la versión del cliente tiquismiquis, pues nos vamos a su rama:

git checkout clientetiquismiquis

y fusionamos con master

git merge master

Auto-merging main.cpp
CONFLICT (content): Merge conflict in main.cpp
Automatic merge failed; fix conflicts and then commit the result.

Leches!!! resulta que no puede fusionarlas automáticamente, pues abrimos el archivo en conflicto, lo dejamos bien a mano y seguimos

git add main.cpp

git commit -m “Fusionadas mejoras de master en clientetiquismiquis”

Todo listo 🙂

El problema en este caso es que no estás aislando correctamente las diferentes funciones.

Las directivas del preprocesador pueden aportar mucha flexibilidad al código… peeero distan mucho de ser perfectas:

  • Cuantos más símbolos defines más complicado es mantener el código
  • El código que queda fuera de un #ifdef no se compila, lo que te obliga a realizar varias compilaciones para probar todas las combinaciones (mantenimiento demasiado caro)
  • Los símbolos no tienen tipado, es facil confundirse y poner _CORTE_SECCION__ en vez de __CORTE_SECCION__… y entonces gasta horas en identificar el problema.

Lo recomendable es aislar las diferentes funcionalidades en clases o funciones. Con los nuevos estándares usar plantillas es una opción bastante asequible.

Me explico. Partamos de este fragmento de código:

#ifndef __CORTE_SECCION__
    worker = NULL;
#else
    multiWorker = NULL; 
#endif

// ...

#ifndef __CORTE_SECCION__
if (worker)
{
    disconnect(worker);
    delete worker;
    worker = NULL;
}
#else
if (multiWorker)
{
    disconnect(multiWorker);
    delete multiWorker;
    multiWorker = NULL;
}
#endif

Mejorarlo y aislar el código aquí es relativamente sencillo.

Lo primero que haría sería definir una constante en base a __CORTE_SECCION__:

#ifdef __CORTE_SECCION__
  constexpr bool IsMultiWorker = false;
#else
  constexpr bool IsMultiWorker = true;
#endif

A continuación podemos crear una colección de plantillas para los diferentes casos de uso (dos en este caso). Nota que no has indicado el tipo de worker y multiworker. Asumiré que son Worker y Multiworker.

El caso, nos interesa crear una herramienta que nos permita crear un Worker o un Multiworker según las circunstancias:

template<bool>
struct MultiWorkerTraits;

template<>
struct MultiWorkerTraits<false>
{
  using type = Worker;
};

template<>
struct MultiWorkerTraits<true>
{
  using type = MultiWorker;
};

Y seguidamente, las funciones de desconexión. Como la lógica a ejecutar es la misma nos basta con una única plantilla:

template<class T>
void Disconnect(T & worker)
{
  if( worker )
  {
    disconnect(worker);
    delete worker;
    worker = nullptr;
  }
}

Ya tenemos todos los mimbres listos, ya solo falta acometer cambios en el fragmento original de código:

typename MultiWorkerTraits<IsMultiWorker>::type * worker = nullptr;

// ...

Disconnect(worker);

Fuente

Related Posts:

Declarar un array de structs de tamaño dinamico – c++
Pregunta: buenas, lo que quiero conseguir es declarar un struct con array que tenga su tamaño dinamico, pero cuando lo hago el programa se me ...
Problemas con el registro de un archivo .tlb – c# windows vb6
Pregunta: La situación es la siguiente: He creado un pequeño proyecto de librería de clases en C# que me permita realizar ciertas operaciones. El nombre del ...
Uso de js y c# en unity. ¿Igual rendimiento? – javascript c# unity3d
Pregunta: Estoy comenzando con unity . Y veo que se pueden usar c# y js para programar. Mi pregunta es si tanto c# como js ...
Cómo puedo incluir librería beecrypt en un proyecto en C – c
Pregunta: Tengo un archivo .lib (librería) y quiero usarla en un proyecto de C. Para ser más especifica estoy intentando instalar beecrypt que es una librería ...
Ocultar y Mostrar con Mapa de Google – javascript c# asp.net
Pregunta: Tengo un div en mi página ASP.NET que contiene un Mapa de Google, y necesito mostrarlo y ocultarlo pero no me funciona. Este es el ...
para que sirve #ifdef_MSDOS_ en c++? – c++
Pregunta: He tenido problemas porque donde trabajo usan una versión de dev c++ 4.9 y yo uso en mi hogar la 5.1, ...
¿Como instalar C# en SublimeText? – c# sublimetext3 sublimetext
Pregunta: El problema es que actualmente quiero programar sobre esta tecnologia, pero no quiero descargar aun el visual studio porque consume recursos y es bastante ...
Consulta sobre git – git github
Pregunta: Tengo un repositorio remoto https://github.com/xxxx/yyy.git En el mismo host donde estoy ubicado habia creado la repo y pusheado , me pidio el nick y password ...
Thread en c++ error compilacion – c++
Pregunta: Estoy empezando con threads y he estado siguien varios tutos y creo que esta todo bien, pero a la hora de ejecutarlo me da ...
¿Es posible capturar un segfault con try/catch? – c++ try-catch
Pregunta: Para comprobar si es posible hice lo siguiente: try { int *x = 0; *x = 1234; } catch(...) { ...
Conexion C# con PostgreSQL mediante proveedor Npgsql – c# postgresql
Pregunta: Hola el problema es que la conexión esta bien solo cuando estoy utilizando el ODBC, pero cuando lo cambio al proveedor de PostgreSQL Npgsql, ...
Construcción extraña: objeto = funcion1() && funcion2() ¿Posible? – c#
Pregunta: acabo de encontrarme en una documentación una construcción como esta: var pose = Body.LeftHand.Near(Body.Head) && Body.LeftArm.Bended(90); posees una objeto que debe crearse a partir de la ...
Cómo importar datos de un Excel a DataGrid pero iniciarlo en la segunda fila? – c# sql-server postgresql
Pregunta: Disculpen una duda, como cargar de excel un formato iniciando en la segunda fila? tengo este código solamente que el excel esta justificado en ...
No completa el ciclo foreach – c#
Pregunta: Estoy haciendo un método para invertir palabras que contengan 5 o mas letras. El problema que tengo es que si mi cadena tiene mas ...
Obtener elementos específicos de un array – c array optimización
Pregunta: Buenas, si yo por ejemplo hago: char buf; fgets(buf, 1024, stdin); ¿Puedo coger los caracteres que escribí del array sin coger los elementos que no utilicé? ¿O ...

Add a Comment

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *