← Back to list

Do C++98 para o C++11: As Primeiras 5 Coisas Que Vais Encontrar

Se fizeste a 42, a tua mente foi formatada por regras de sobrevivência muito claras. Aprendeste a programar com o fantasma do Norminette a…

Ohana Bento · 2026-06-05 20:07 · 3 claps · 4.4 min read
#cpp #cplusplus #software-development #42-network #42-luanda
Open on Medium ↗

Do C++98 para o C++11: As Primeiras 5 Coisas Que Vais Encontrar

Se fizeste a 42, a tua mente foi formatada por regras de sobrevivência muito claras. Aprendeste a programar com o fantasma do Norminette a vigiar as tuas linhas de código, passaste semanas a recriar funções básicas em C e, quando finalmente chegaste aos módulos de C++, foste atirado para o ringue com o C++98.

A regra de ouro é simples: “Se deste new, tens de dar delete". Aprendemos a caçar memory leaks com o valgrind como se a nossa vida dependesse disso (e a nossa nota dependia mesmo).

Depois do common core, abres o repositório de produção de uma empresa moderna.

A sensação é de ter saído de uma máquina do tempo. Nada de delete? O que é este auto? Quem autorizou esta lambda no meio do código de produção?

Calma. O teu esforço na 42 não foi em vão. O C++ atual é que parou de ser hostil. Este artigo é para quem está a viver esse choque cultural agora, e para explicar o porquê de cada mudança, não só o como.

1. O “Ranged-for”: Adeus aos contadores da Piscine

Na 42, estragámos os dedos a digitar loops baseados em índices. O clássico dos módulos de C++ era isto:

for (size_t i = 0; i < meuVetor.size(); i++) {
    std::cout << meuVetor[i] << std::endl;
}

Se submeteres isto num code review hoje, o teu tech lead vai perguntar se vieste dos anos 90. No C++11 em diante, o compilador trata da burocracia por ti:

for (const auto& item : meuVetor) {
    std::cout << item << std::endl;
}

Para quem passou a vida a verificar se o i passava do limite do vetor para não levar um Segmentation Fault, ver o C++ resolver isto com dois pontos (:) chega a ser reconfortante. Mas o motivo real desta mudança não é conveniência — é segurança. O índice manual é uma fonte clássica de off-by-one errors e acessos fora dos limites. O ranged-for elimina essa categoria de bugs por completo.

2. Smart pointers: a morte do new e o fim das noites com o Valgrind

Toda a gente que passou pela 42 tem traumas com o valgrind --leak-check=full. Esquecer um free significava reprovar a avaalição de um colega.

// O estilo que a 42 nos obrigou a dominar
MinhaClasse* objeto = new MinhaClasse();
// ... código ...
delete objeto; // E se lançar uma exceção antes daqui?

Repara no meu comentário. Este é o problema real: em código de produção, entre o new e o delete pode acontecer uma exceção, um return antecipado, ou uma refatoração descuidada. O resultado é um leak que o valgrind na 42 teria apanhado, mas que em produção pode viver durante meses.

A solução moderna são os smart pointers:

// unique_ptr: um único dono, destruído automaticamente ao sair do escopo
auto objeto = std::make_unique<MinhaClasse>();

// shared_ptr: quando a memória precisa de ser partilhada entre vários donos
auto partilhado = std::make_shared<MinhaClasse>();

// weak_ptr: referência sem ownership, evita ciclos de referências
std::weak_ptr<MinhaClasse> referencia = partilhado;

O compilador sabe quando o objeto já não é necessário e injeta a limpeza automaticamente — é o padrão RAII que a 42 te ensinou. A diferença é que agora não precisas de o gerir manualmente.

3. auto: O compilador finalmente aprendeu a ler o contexto

Na 42, escrevíamos tipos gigantescos à mão por causa do rigor do C++98:

std::vector<std::string>::const_iterator it = lista.begin();

Toda a gente sabia que lista.begin() devolve um iterator. O compilador também sabia. Mas o C++98 obrigava-nos a digitar a declaração completa na mesma — se não o fizesses, não compilava.

No C++ moderno, auto resolve isso:

auto it = lista.begin();

O compilador olha para o lado direito da igualdade e deduz o tipo. Menos ruído, mesma performance, zero custo em runtime — a dedução acontece inteiramente em tempo de compilação.

Um aviso importante: auto é uma ferramenta, não uma desculpa para não saber os tipos. Num code review, se não conseguires explicar o tipo que o auto vai deduzir, és tu o problema — não o auto. A 42 deu-te exatamente o background para usar esta ferramenta com consciência.

4. nullptr: o fim da crise de identidade do zero

No início da 42, o NULL era o nosso melhor amigo. Nos módulos de C++98, ensinaram-nos a usar o 0 puro para inicializar pointers nulos para evitar problemas do C.

O problema? O 0 é simultaneamente um inteiro e um pointer nulo. Isto criava ambiguidades genuínas em sobrecarga de funções:

void processa(int valor);
void processa(char* ptr);
processa(NULL); // Qual das duas funções é chamada?

A resposta dependia do compilador. Comportamento indefinido disfarçado de código legítimo — exatamente o tipo de bug que aparecia nos projetos da 42 e ninguém conseguia explicar.

O C++ moderno resolve isto com nullptr:

processa(nullptr); // Inequivocamente a versão com pointer. Sempre.

nullptr é um tipo próprio (std::nullptr_t) que só converte para pointers, nunca para inteiros. Limpo, seguro, sem ambiguidades.

5. Lambdas: os functors que nunca quiseste escrever

Se fizeste o módulo 08 ou 09 da 42, já escreveste um functor — uma struct com operator() sobrecarregado para passar comportamento como argumento:

struct MaiorQue42 {
    bool operator()(int n) const {
        return n > 42;
    }
};
std::vector<int> resultado;
std::copy_if(numeros.begin(), numeros.end(),
             std::back_inserter(resultado), MaiorQue42());

Funciona. É verboso, ocupa várias linhas e precisas de sair do contexto para definir a struct. Em C++11, o mesmo comportamento escreve-se assim:

auto resultado = std::vector<int>{};
std::copy_if(numeros.begin(), numeros.end(),
             std::back_inserter(resultado),
             [](int n) { return n > 42; });

A sintaxe [](){} é uma lambda: uma função anónima definida no próprio sítio onde é usada. O [] é a capture list: define o que a lambda pode ver do contexto exterior. [=] captura tudo por valor, [&] por referência, [x] captura apenas x.

Tu já entendes o conceito por baixo porque escreveste os functors. A lambda é apenas a versão sem burocracia.

O C++ moderno não veio anular o que aprendeste na 42. Veio tirar o peso do trabalho repetitivo das costas — para que possas concentrar o teu conhecimento onde ele realmente importa.

Há muito mais território a explorar no C++11 e além. Move semantics e rvalue references, concorrência nativa com std::thread e std::mutex em vez de pthreads, uniform initialization, override e final, constexpr, e os algoritmos do STL modernizados com lambdas. Este artigo não pretende ser um guia exaustivo. Pretende ser a linha de partida até porque eu comecei também a maravilhar-me com tudo isto agora.

Se vieste da 42 ou de um percurso parecido e estás nesta transição, deixa um comentário. Estou curiosa para saber como foi o teu choque de realidade.


메타데이터
post_id
5e677195bf3b
slug
do-c-98-para-o-c-11-as-primeiras-5-coisas-que-vais-encontrar-5e677195bf3b
url
https://medium.com/@ohanalweji/do-c-98-para-o-c-11-as-primeiras-5-coisas-que-vais-encontrar-5e677195bf3b
canonical_url
https://medium.com/@ohanalweji/do-c-98-para-o-c-11-as-primeiras-5-coisas-que-vais-encontrar-5e677195bf3b
author_url
https://medium.com/@ohanalweji
status
ok
fetched_at
2026-06-10 13:37:17