O que é POD em C++ e por que há debate sobre ele?
Se você já escreveu código em C++ que trabalha com memória bruta, serializa dados ou interage com bibliotecas C, certamente já se deparou com a misteriosa sigla POD (Plain Old Data). Em tradução livre — "dados simples antigos". Mas essa simplicidade é enganosa. No Stack Overflow, a pergunta "What are POD types in C++?" acumula milhares de visualizações, e nos comentários há acalorados debates sobre o que é ou não é POD.
Neste artigo, vamos analisar o que são tipos POD em C++, quais erros até desenvolvedores experientes cometem e como evitá-los. Você aprenderá a usar corretamente memcpy, por que nem todas as classes triviais são POD e como não "matar" a performance devido a um layout incorreto.
Breve história: do C ao C++
POD é uma herança da linguagem C. Quando o C++ surgiu, era necessário garantir compatibilidade reversa. As estruturas do C precisavam funcionar em C++ sem alterações. Assim nasceu o conceito de Plain Old Data — tipos que se comportam como em C: possuem construtor trivial, destrutor, cópia e layout padrão.
Com o lançamento dos padrões C++11, C++14 e C++20, os requisitos para POD se tornaram mais rigorosos. Agora não é apenas "uma estrutura sem métodos", mas um conjunto complexo de regras. Vamos analisá-las em ordem.
Top 5 erros ao trabalhar com tipos POD
1. Confusão entre "trivial" e "POD"
Muitos pensam que se uma classe é trivial, ela automaticamente é POD. Isso não é verdade. POD é a interseção de duas propriedades: trivialidade (trivial) e layout padrão (standard layout).
// Trivial, mas não POD (layout padrão violado)class NotPOD { int x;public: virtual void foo() {} // função virtual};
// Trivial e PODstruct RealPOD { int x; float y;};No primeiro caso, o compilador adiciona um ponteiro vtable, o que viola o layout padrão. Essa classe não pode ser copiada com segurança via memcpy.
2. Uso de memcpy com tipos não-POD
Um erro clássico é copiar um objeto via memcpy quando ele não é POD. Isso leva a comportamento indefinido.
#include <cstring>#include <iostream>
struct SafePOD { int a; double b;};
struct Unsafe { std::string s; // não-POD: possui construtor, destrutor};
int main() { SafePOD p1{1, 2.5}; SafePOD p2; std::memcpy(&p2, &p1, sizeof(SafePOD)); // OK
Unsafe u1{"hello"}; Unsafe u2; std::memcpy(&u2, &u1, sizeof(Unsafe)); // Erro! Comportamento indefinido}Como evitar: sempre verifique std::is_pod_v<T> antes de usar memcpy. Em C++20, use std::is_trivial_v e std::is_standard_layout_v separadamente.
3. Ignorar o alinhamento (alignment)
Tipos POD em C++ garantem que seu layout seja previsível. Mas isso não significa que o alinhamento possa ser ignorado. O erro ocorre quando se tenta empacotar manualmente uma estrutura para economizar memória.
#pragma pack(push, 1)struct Packed { char c; int i; // violação de alinhamento};#pragma pack(pop)Embora formalmente Packed possa ser POD, o acesso a i pode ser lento ou até causar SIGBUS em algumas arquiteturas (ARM, por exemplo).
Como evitar: use alignas e std::alignment_of para controlar o alinhamento, mas não abuse de #pragma pack sem necessidade.
4. Herança e POD
Muitos pensam que se uma estrutura herda de outra estrutura POD, ela também é POD. Isso é verdade apenas sob certas condições.
Blogs
Book Recommendations
Leia também
Monorepositório com Swift: organização de código para iOS e macOS
Como identificar o tipo de requisição HTTP em PHP: GET, POST, PUT, DELETE
Data class em Kotlin: por que não podem ser herdadas e como contornar
Refatoração de código Swift: quando é necessária e como fazer corretamente
Verificação de existência de arquivo em Go: velocidade, erros e melhores práticas