Validação de dados em C++: visão geral de bibliotecas e abordagens práticas
A validação de dados é um dos principais aspectos do desenvolvimento de software confiável em C++. A verificação correta dos dados de entrada permite prevenir erros de execução, vulnerabilidades e comportamento indefinido. Ao contrário de linguagens com tipagem dinâmica, o C++ exige do desenvolvedor um controle explícito de tipos e formatos. Neste artigo, veremos tanto métodos manuais quanto bibliotecas especializadas que simplificam a validação.
1. Validação manual: técnicas básicas
A maneira mais simples é verificar os dados usando instruções condicionais. Essa abordagem é boa para projetos pequenos, mas rapidamente se torna complicada.
#include <iostream>#include <string>#include <cctype>
bool validateEmail(const std::string& email) { if (email.empty()) return false; size_t atPos = email.find('@'); if (atPos == std::string::npos || atPos == 0) return false; size_t dotPos = email.rfind('.'); if (dotPos == std::string::npos || dotPos <= atPos + 1) return false; if (dotPos == email.length() - 1) return false; return true;}
int main() { std::string testEmail = "user@example.com"; std::cout << (validateEmail(testEmail) ? "Valid" : "Invalid") << std::endl; return 0;}Desvantagens: complexidade de manutenção, duplicação de código, falta de uma interface unificada.
2. Biblioteca libvalidate
libvalidate é uma biblioteca leve para validação declarativa de dados em C++17 e superior. Ela permite descrever regras de verificação em estilo encadeado, semelhante aos validadores em PHP ou Python.
Instalação
A biblioteca é distribuída como header-only. Basta copiar validate.hpp para o projeto ou conectá-la via CMake:
# Exemplo FetchContentinclude(FetchContent)FetchContent_Declare(libvalidate GIT_REPOSITORY https://github.com/username/libvalidate.git GIT_TAG v1.0.0)FetchContent_MakeAvailable(libvalidate)Exemplo de uso
#include "validate.hpp"#include <iostream>#include <string>
int main() { using namespace validate;
// Validação de número (idade) int age = 25; auto ageResult = check(age) .min(18, "A idade deve ser no mínimo 18 anos") .max(120, "A idade deve ser no máximo 120 anos");
if (!ageResult.valid()) { std::cerr << ageResult.error() << std::endl; }
// Validação de string (senha) std::string password = "P@ssw0rd"; auto passResult = check(password) .minLength(8, "A senha deve conter no mínimo 8 caracteres") .matches(R"((?=.*[A-Z])(?=.*[a-z])(?=.*\\d).*)", "A senha deve conter letras maiúsculas, minúsculas e dígitos");
if (!passResult.valid()) { std::cerr << passResult.error() << std::endl; }
// Validação combinada de objeto struct User { std::string name; int age; std::string email; };
User user{"Alice", 30, "alice@example.com"}; auto userResult = check(user) .field(&User::name, "name") .minLength(2) .maxLength(50) .field(&User::age, "age") .range(18, 100) .field(&User::email, "email") .email(); // verificação de email embutida
if (!userResult.valid()) { for (const auto& err : userResult.errors()) { std::cerr << err.field << ": " << err.message << std::endl; } }
return 0;}Características:
- Suporte a regras embutidas:
min,max,range,email,regex,notEmpty. - Possibilidade de criar