January 29, 2026 (2mo ago)

Classes vs Structs: Um Guia de Desempenho para Desenvolvedores

Descubra as diferenças fundamentais entre classes e structs. Saiba quando usar cada uma para código limpo e de alto desempenho em C#, Swift, C++ e mais.

← Back to blog
Cover Image for Classes vs Structs: Um Guia de Desempenho para Desenvolvedores

Descubra as diferenças fundamentais entre classes e structs. Saiba quando usar cada uma para código limpo e de alto desempenho em C#, Swift, C++ e mais.

Classes vs Structs: Um Guia de Desempenho para Desenvolvedores

Resumo: Descubra as diferenças fundamentais entre classes e structs. Saiba quando usar cada uma para código limpo e de alto desempenho em C#, Swift, C++ e mais.

Introdução

A diferença fundamental entre classes e structs é simples, mas decisiva: classes são tipos por referência e structs são tipos por valor. Essa distinção determina o layout de memória, o comportamento de cópia e o desempenho em tempo de execução em linguagens como C#, C++ e Swift. Entender quando escolher um ou outro é essencial para código previsível e sistemas de alto desempenho.

Entendendo a Diferença Fundamental

Quando você instancia uma classe, a variável que você possui é uma referência que aponta para o objeto no heap. Copiar essa variável copia a referência; múltiplas referências podem apontar para o mesmo objeto, então alterações feitas por uma referência são visíveis através de outras. Essa semântica por referência é uma das principais razões pelas quais classes são usadas para entidades com identidade.1

Uma struct representa os próprios dados. Criar uma struct produz um pacote concreto de valores — frequentemente armazenado na pilha ou embutido em arrays — de modo que copiar uma struct gera um duplicado independente. Modificar a cópia não afeta o original, o que torna structs ótimas para valores simples e imutáveis.1

Para mais sobre encapsulamento e design de objetos, veja nosso guia sobre encapsulamento orientado a objetos: https://cleancodeguy.com/blog/object-oriented-encapsulation.

Diagram illustrating Structs stored on the Stack and Classes referenced from the Stack to the Heap.

Comparação Rápida: Tipos por Referência vs Tipos por Valor

CaracterísticaClasse (Tipo por Referência)Struct (Tipo por Valor)
Localização na memóriaHeap; objeto referenciado por ponteiro.Pilha ou inline; a variável é os dados.
AtribuiçãoCopia a referência, não o objeto.Copia todo o valor.
Tempo de vidaGerenciado por coleta de lixo (ou deleção manual em algumas linguagens).Desalocado quando sai de escopo ou armazenado inline.
Identidade vs valorTem identidade; múltiplas referências podem apontar para uma instância.Representa um valor; igualdade frequentemente baseada nos dados.

Use uma classe quando você precisar de identidade compartilhada. Use uma struct quando precisar de um valor simples e autocontido que possa ser copiado sem efeitos colaterais.

Essa base informa trade-offs de desempenho mais profundos — alocação em heap vs pilha, localidade de cache e pressão sobre a coleta de lixo — que exploramos a seguir.

Como a Alocação de Memória Ditai a Velocidade

O layout de memória afeta a eficiência da CPU, o throughput e a latência. Um acesso a classe normalmente envolve uma indireção: um ponteiro na pilha referencia dados no heap. Essa busca extra adiciona custo e pode prejudicar o comportamento do cache. Structs, armazenadas diretamente onde a variável vive, frequentemente evitam essa indireção e permitem layouts de memória mais compactos com melhor localidade de cache.1

Diagram comparing Struct/Stack and Class/Heap memory allocation, highlighting contiguous memory, garbage collection, and speed differences.

Custos da Coleta de Lixo

Objetos no heap estão sujeitos à coleta de lixo. Ciclos de GC podem pausar a execução, aumentando a latência em sistemas em tempo real ou de alto throughput. A alocação frequente de objetos de classe de curta duração aumenta a pressão sobre o GC e a sobrecarga da CPU. Usar tipos por valor para muitos objetos pequenos e de curta duração reduz o churn no heap e o trabalho do GC.3

A alocação no heap adiciona potencial sobrecarga do GC. Structs evitam essa sobrecarga quando permanecem como tipos por valor e sem boxing.

Isto é especialmente importante em sistemas projetados para escala e responsividade — reduzir alocações reduz diretamente a atividade do GC e pode suavizar o desempenho em tempo de execução.

Localidade de Cache e Throughput

CPUs modernas dependem de caches. Layouts sequenciais — como arrays de structs — melhoram acertos de cache e throughput. Alocações separadas no heap para cada instância de classe espalham os dados pela memória, aumentando faltas de cache e desacelerando o processamento. Para loops apertados e pipelines de processamento de dados, layouts contíguos de valores são uma vantagem significativa.5

A Armadilha do Boxing

Boxing ocorre quando um tipo por valor é convertido para um tipo por referência (por exemplo, quando colocado em uma coleção que espera objetos). Boxing aloca um objeto no heap e copia o valor para dentro dele, anulando as vantagens de desempenho da struct e aumentando a carga do GC. Evitar o boxing é um princípio central do uso eficiente de tipos por valor.4

Como as Linguagens Diferem: C#, C++ e Swift

Diferentes linguagens impõem convenções e capacidades distintas. Conhecer as regras específicas de cada linguagem evita aplicar regras de uma linguagem cegamente a outra.

Diagram comparing C#, C++, and Swift programming language characteristics, focusing on reference vs value types and object flexibility.

C#: Modelo Claro de Referência vs Valor

Em C#, class = tipo por referência e struct = tipo por valor. Use classes para entidades com identidade (por exemplo, Customer ou DatabaseConnection) e structs para valores pequenos e imutáveis (por exemplo, Point, Color). Manter structs pequenas e imutáveis evita bugs sutis e sobrecarga de cópia.1

Erros comuns incluem criar structs grandes ou mutáveis; ambos levam a bugs surpreendentes ou regressões de desempenho. Siga a diretriz de structs imutáveis e pequenas ao otimizar em C#.

C++: Convenção em Vez de Restrição da Linguagem

Em C++, a única diferença sintática entre struct e class é a acessibilidade padrão. Ambos podem ser alocados na pilha ou no heap, ter métodos e suportar herança. A convenção é usar struct para agregados de dados simples e class para objetos encapsulados e gerenciamento de recursos via RAII.

Essa flexibilidade significa que desenvolvedores C++ devem confiar em convenções e escolhas de design em vez de distinções de valor/referência impostas pela linguagem. Para orientação sobre padrões de polimorfismo e herança, veja nossas notas de design em C++: https://cleancodeguy.com/blog/polymorphism-vs-inheritance.

Swift: Orientada para Valor por Padrão

Swift incentiva preferir structs para a maioria dos tipos personalizados. Structs em Swift suportam métodos, extensions e conformidade a protocolos, tornando-as poderosas e ao mesmo tempo defaults seguros. Escolha classes apenas quando semântica por referência, identidade ou interoperabilidade com Objective-C for necessária.2

Esse design que prioriza valores incentiva imutabilidade e um raciocínio mais simples sobre fluxo de dados, particularmente em código concorrente.

Quando Escolher uma Struct para Máxima Eficiência

Structs são ideais para pacotes pequenos e imutáveis de dados cuja identidade é definida inteiramente por seus valores. Exemplos típicos:

  • Dados geométricos: Point2D ou RGBColor
  • Valores financeiros: Money (quantia + moeda)
  • Pequenos DTOs usados em pipelines de alto throughput

Uma diretriz prática de tamanho é a regra dos “16–32 bytes”: se os campos de uma struct couberem aproximadamente nessa faixa, o custo de cópia é modesto e frequentemente mais barato que a alocação no heap. Se uma struct crescer muito ou precisar ser mutável, uma classe provavelmente é a melhor escolha.5

Guide on choosing structs for small, value-type data like RGB, 2D Point, and Money, with a 16-byte guideline.

Regras de Imutabilidade e Tamanho

  • Prefira structs imutáveis: valores devem ser criados uma vez e substituídos em vez de mutados.
  • Mantenha structs pequenas: copiar structs grandes com frequência pode se tornar mais caro do que passar referências.

Essas regras ajudam a evitar bugs silenciosos (originados por cópias mutáveis) e armadilhas de desempenho (por excesso de cópia ou boxing).

Armadilhas Comuns e Refatoração

Dois problemas comuns são structs mutáveis e boxing excessivo.

Structs mutáveis levam a comportamentos surpreendentes porque modificações afetam apenas uma cópia. Refatore structs mutáveis em structs imutáveis que retornem novas instâncias para alterações de estado.

Boxing ocorre implicitamente em muitas APIs e coleções; identifique e remova hotspots de boxing para preservar os benefícios de desempenho das structs.

Exemplo: Refatorar um Point Mutável para uma Struct Imutável (C#)

// PITFALL: Mutable struct public struct MutablePoint { public int X { get; set; } public int Y { get; set; }

public void Move(int dx, int dy)
{
    X += dx;
    Y += dy;
}

}

// REFACTOR: Immutable struct public readonly struct ImmutablePoint { public int X { get; } public int Y { get; }

public ImmutablePoint(int x, int y)
{
    X = x;
    Y = y;
}

public ImmutablePoint MovedBy(int dx, int dy)
{
    return new ImmutablePoint(X + dx, Y + dy);
}

}

Essa refatoração torna a intenção explícita e elimina corrupções acidentais de estado. Para mais práticas de clean-coding, veja nosso guia de princípios: https://cleancodeguy.com/blog/clean-coding-principles.

Perguntas Frequentes (Q&A Conciso)

P1: Quando devo preferir uma struct em vez de uma classe?

R: Prefira uma struct quando o tipo for pequeno, imutável e representar um valor em vez de uma identidade. Structs brilham para dados simples como pontos, cores ou pequenos DTOs.

P2: Quais armadilhas de desempenho devo observar?

R: Evite structs mutáveis, structs grandes (custo de cópia) e boxing em objetos do heap — esses fatores anulam os benefícios dos tipos por valor e podem prejudicar o desempenho.

P3: Como as diferenças entre linguagens afetam minha escolha?

R: Siga as convenções da linguagem: C# impõe valor vs referência; C++ usa convenção; Swift prefere tipos por valor por padrão. Aprenda as regras da plataforma antes de aplicar padrões entre linguagens.12


No Clean Code Guy, ajudamos equipes a aplicar esses princípios em bases de código reais. Nossos Codebase Cleanups e AI-Ready Refactors tornam o software mais rápido, seguro e mais fácil de manter. Visite https://cleancode.com para saber mais.

1.
Microsoft Docs, “Choosing between classes and structs,” https://learn.microsoft.com/en-us/dotnet/standard/choosing-between-class-and-struct
2.
Apple Developer Documentation, “Structures and Classes,” https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html
4.
5.
NDepend Blog, “Class vs Struct in C#: Making Informed Choices,” https://blog.ndepend.com/class-vs-struct-in-c-making-informed-choices/
← Back to blog
🙋🏻‍♂️

IA escreve código.
Você faz durar.

Na era da aceleração da IA, código limpo não é apenas uma boa prática — é a diferença entre sistemas que escalam e bases de código que entram em colapso sob seu próprio peso.