Introducción: por qué el código limpio es importante para C++
\n\nC++ es un lenguaje potente y flexible que permite escribir tanto código de sistema de alto rendimiento como soluciones de aplicación complejas. Sin embargo, esta flexibilidad a menudo se convierte en caos: funciones sobrecargadas, conversiones implícitas, gestión manual de memoria y macros pueden convertir un proyecto en un "pantano" en pocos meses. El concepto de Clean Code (código limpio), popularizado por Robert Martin, es totalmente aplicable a C++, pero teniendo en cuenta las particularidades del lenguaje.
\n\nEn este artículo, analizaremos los principios clave del código limpio en C++ y mostraremos su aplicación con ejemplos reales. Aprenderá a escribir código que sea fácil de leer, probar y mantener.
\n\n1. Nomenclatura y estructura: la base de la legibilidad
\n\n1.1. Nombres significativos de variables y funciones
\n\nLa primera regla del código limpio es que el nombre debe revelar la intención. En C++, esto es especialmente importante debido a las sobrecargas y las plantillas.
\n\nEjemplo incorrecto:
\n\nint d; // elapsed time in days\nvoid proc(int a, int b); // ¿qué son a y b?\n\nEjemplo correcto:
\n\nint elapsedTimeInDays;\nvoid processData(const std::vector<int>& inputData, int maxIterations);\n\n1.2. Clases y espacios de nombres
\n\nUtilice espacios de nombres para la agrupación lógica. Evite las variables globales: es un antipatrón.
\n\nnamespace network {\n class TcpConnection {\n public:\n void connect(const std::string& host, int port);\n void send(const std::vector<char>& data);\n private:\n int socket_;\n };\n} // namespace network\n\n2. Funciones: pequeñas y con una sola responsabilidad
\n\n2.1. Principio de responsabilidad única (SRP)
\n\nUna función debe hacer solo una cosa. Si una función hace más de una acción, divídala.
\n\nEjemplo incorrecto:
\n\nvoid processOrder(Order& order) {\n // validación\n if (order.total < 0) throw std::invalid_argument("Negative total");\n // guardar en BD\n database.save(order);\n // enviar email\n emailService.send(order.customerEmail, "Order confirmed");\n}\n\nEjemplo correcto:
\n\nbool validateOrder(const Order& order);\nvoid saveOrderToDatabase(const Order& order);\nvoid sendConfirmationEmail(const Order& order);\n\nvoid processOrder(Order& order) {\n if (!validateOrder(order)) return;\n saveOrderToDatabase(order);\n sendConfirmationEmail(order);\n}\n\n2.2. Evite efectos secundarios
\n\nUna función no debe modificar el estado global sin necesidad explícita. Use referencias constantes y devuelva valores, en lugar de modificar argumentos.
\n\n// Malo: modifica el vector de entrada\nvoid addPrefix(std::vector<std::string>& words, const std::string& prefix) {\n for (auto& word : words) {\n word = prefix + word;\n }\n}\n\n// Bueno: devuelve un nuevo vector\nstd::vector<std::string> addPrefix(const std::vector<std::string>& words, const std::string& prefix) {\n std::vector<std::string> result;\n result.reserve(words.size());\n for (const auto& word : words) {\n result.push_back(prefix + word);\n }\n return result;\n}\n\n3. Gestión de memoria y RAII
\n\n3.1. Use punteros inteligentes
\n\nEn C++ moderno (C++11 y posteriores), la gestión manual de memoria mediante new/delete se considera obsoleta. Use std::unique_ptr y std::shared_ptr.
// Malo: posible fuga de memoria\nvoid process() {\n Resource* res = new Resource();\n // ... si aquí hay una excepción, la memoria se fuga\n delete res;\n}\n\n// Bueno: liberación automática\nvoid process() {\n a