Introdução: por que o código limpo é importante para C++
\n\nC++ é uma linguagem poderosa e flexível que permite escrever tanto código de sistema de alta eficiência quanto soluções aplicadas complexas. No entanto, essa flexibilidade muitas vezes resulta em caos: funções sobrecarregadas, conversões implícitas, gerenciamento manual de memória e macros podem transformar um projeto em um "pântano" em poucos meses. O conceito de Clean Code (código limpo), popularizado por Robert Martin, é totalmente aplicável ao C++, mas levando em conta as especificidades da linguagem.
\n\nNeste artigo, vamos analisar os princípios-chave do código limpo em C++ e mostrar sua aplicação em exemplos reais. Você aprenderá a escrever código que seja fácil de ler, testar e manter.
\n\n1. Nomenclatura e estrutura: a base da legibilidade
\n\n1.1. Nomes significativos para variáveis e funções
\n\nA primeira regra do código limpo é que o nome deve revelar a intenção. Em C++, isso é especialmente importante devido à presença de sobrecargas e templates.
\n\nExemplo ruim:
\n\nint d; // tempo decorrido em dias\nvoid proc(int a, int b); // o que são a e b?\n\nExemplo bom:
\n\nint elapsedTimeInDays;\nvoid processData(const std::vector<int>& inputData, int maxIterations);\n\n1.2. Classes e namespaces
\n\nUse namespaces para agrupamento lógico. Evite variáveis globais — isso é um antipadrão.
\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. Funções: pequenas e com uma única responsabilidade
\n\n2.1. Princípio da Responsabilidade Única (SRP)
\n\nUma função deve fazer apenas uma coisa. Se uma função faz mais de uma ação — divida-a.
\n\nExemplo ruim:
\n\nvoid processOrder(Order& order) {\n // validação\n if (order.total < 0) throw std::invalid_argument("Total negativo");\n // salvar no banco de dados\n database.save(order);\n // enviar email\n emailService.send(order.customerEmail, "Pedido confirmado");\n}\n\nExemplo bom:
\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 efeitos colaterais
\n\nUma função não deve alterar o estado global sem necessidade explícita. Use referências constantes e retorne valores, em vez de modificar argumentos.
\n\n// Ruim: modifica o vetor 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// Bom: retorna um novo vetor\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. Gerenciamento de memória e RAII
\n\n3.1. Use ponteiros inteligentes
\n\nNo C++ moderno (C++11 e posteriores), o gerenciamento manual de memória com new/delete é considerado obsoleto. Use std::unique_ptr e std::shared_ptr.
// Ruim: vazamento de memória possível\nvoid process() {\n Resource* res = new Resource();\n // ... se houver uma exceção aqui, a memória vaza\n delete res;\n}\n\n// Bom: liberação automática\nvoid process() {\n a