Clean Code em C++: princípios e exemplos na prática

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: por que o código limpo é importante para C++

\n\n

C++ é 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\n

Neste 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\n

1. Nomenclatura e estrutura: a base da legibilidade

\n\n

1.1. Nomes significativos para variáveis e funções

\n\n

A 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\n

Exemplo ruim:

\n\n
int d; // tempo decorrido em dias\nvoid proc(int a, int b); // o que são a e b?
\n\n

Exemplo bom:

\n\n
int elapsedTimeInDays;\nvoid processData(const std::vector<int>& inputData, int maxIterations);
\n\n

1.2. Classes e namespaces

\n\n

Use namespaces para agrupamento lógico. Evite variáveis globais — isso é um antipadrão.

\n\n
namespace 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\n

2. Funções: pequenas e com uma única responsabilidade

\n\n

2.1. Princípio da Responsabilidade Única (SRP)

\n\n

Uma função deve fazer apenas uma coisa. Se uma função faz mais de uma ação — divida-a.

\n\n

Exemplo ruim:

\n\n
void 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\n

Exemplo bom:

\n\n
bool 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\n

2.2. Evite efeitos colaterais

\n\n

Uma 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\n

3. Gerenciamento de memória e RAII

\n\n

3.1. Use ponteiros inteligentes

\n\n

No 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.

\n\n
// 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                

Blogs

Book Recommendations