---
title: "Esquecer defer — Como Resolver em Zig"
url: "https://ziglang.com.br/erros/esquecer-defer-como-resolver-em-zig/"
markdown_url: "https://ziglang.com.br/erros/esquecer-defer-como-resolver-em-zig.MD"
description: "Entenda o erro comum de esquecer defer em Zig, causando vazamentos de memória e recursos não liberados. Veja padrões corretos de uso."
date: "2026-02-21"
author: "Zig Brasil"
---

# Esquecer defer — Como Resolver em Zig

Entenda o erro comum de esquecer defer em Zig, causando vazamentos de memória e recursos não liberados. Veja padrões corretos de uso.


# Esquecer defer — Como Resolver em Zig

## O Que Este Erro Significa

Esquecer de usar `defer` para liberar recursos é um dos erros mais comuns para iniciantes em Zig. Diferente de linguagens com garbage collector, Zig requer que o programador gerencie manualmente a vida útil de cada recurso alocado. O `defer` é a ferramenta principal para garantir que recursos sejam liberados ao sair de um escopo, independente de como a saída acontece (retorno normal, retorno antecipado ou propagação de erro).

Sem `defer`, o código fica vulnerável a vazamentos de memória, descritores de arquivo não fechados, mutexes não liberados e outros problemas que se acumulam silenciosamente.

## Causas Comuns

### 1. Alocar Memória sem defer free

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const dados = try allocator.alloc(u8, 1024);
    // ERRO: sem defer allocator.free(dados)

    // ... uso dos dados ...
    // Ao sair de main, memória vaza
}
```

### 2. Abrir Arquivo sem defer close

```zig
const std = @import("std");

pub fn main() !void {
    const file = try std.fs.cwd().openFile("dados.txt", .{});
    // ERRO: sem defer file.close()

    var buf: [1024]u8 = undefined;
    const bytes = try file.read(&buf);
    _ = bytes;
    // Descritor de arquivo vaza ao sair
}
```

### 3. Inicializar Coleção sem defer deinit

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    var lista = std.ArrayList(u32).init(allocator);
    // ERRO: sem defer lista.deinit()

    try lista.append(1);
    try lista.append(2);
    // Memória interna da lista vaza
}
```

### 4. Retorno Antecipado sem Limpeza

```zig
const std = @import("std");

fn processar(allocator: std.mem.Allocator) !void {
    const buf = try allocator.alloc(u8, 1024);
    // Sem defer!

    if (buf.len < 2048) {
        return error.BufferPequeno;
        // LEAK: buf nunca é liberado neste caminho
    }

    allocator.free(buf); // Só libera no caminho de sucesso
}
```

### 5. Mutex sem defer unlock

```zig
const std = @import("std");

var mutex = std.Thread.Mutex{};
var dados_compartilhados: u32 = 0;

fn acessar() void {
    mutex.lock();
    // ERRO: sem defer mutex.unlock()

    dados_compartilhados += 1;
    // Se uma exceção/panic acontecer, mutex fica travado para sempre

    mutex.unlock(); // Só funciona se chegar aqui
}
```

## Como Corrigir

### Solucao 1: Padrão alloc + defer free

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const dados = try allocator.alloc(u8, 1024);
    defer allocator.free(dados); // Sempre na linha seguinte ao alloc!

    // Usa dados com segurança
    dados[0] = 42;
    // defer cuida do free automaticamente
}
```

### Solucao 2: Padrão open + defer close

```zig
const std = @import("std");

pub fn main() !void {
    const file = try std.fs.cwd().openFile("dados.txt", .{});
    defer file.close(); // Sempre após abrir!

    var buf: [1024]u8 = undefined;
    const bytes = try file.read(&buf);
    std.debug.print("Lidos {} bytes\n", .{bytes});
    // file é fechado automaticamente
}
```

### Solucao 3: Padrão init + defer deinit

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    var lista = std.ArrayList(u32).init(allocator);
    defer lista.deinit(); // Imediatamente após init!

    var mapa = std.StringHashMap(u32).init(allocator);
    defer mapa.deinit(); // Imediatamente após init!

    try lista.append(42);
    try mapa.put("chave", 100);
}
```

### Solucao 4: errdefer para Limpeza em Caso de Erro

```zig
const std = @import("std");

fn criarRecurso(allocator: std.mem.Allocator) ![]u8 {
    const buf = try allocator.alloc(u8, 1024);
    errdefer allocator.free(buf); // Libera SÓ se retornar erro

    try validar(buf);
    // Se validar falhar, errdefer libera buf
    // Se sucesso, quem chamou é responsável

    return buf; // Transfere propriedade
}

fn validar(buf: []u8) !void {
    _ = buf;
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const recurso = try criarRecurso(allocator);
    defer allocator.free(recurso); // Quem recebeu libera
}
```

### Solucao 5: Padrão lock + defer unlock

```zig
const std = @import("std");

var mutex = std.Thread.Mutex{};
var contador: u32 = 0;

fn incrementar() void {
    mutex.lock();
    defer mutex.unlock(); // Sempre após lock!

    contador += 1;
    // Mesmo que algo dê errado, mutex é liberado
}
```

### Solucao 6: Múltiplos defers (Ordem LIFO)

```zig
const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const a = try allocator.alloc(u8, 100);
    defer allocator.free(a); // Executado por último

    const b = try allocator.alloc(u8, 200);
    defer allocator.free(b); // Executado segundo

    const file = try std.fs.cwd().openFile("dados.txt", .{});
    defer file.close(); // Executado primeiro

    // Ordem de execução dos defers: file.close, free(b), free(a), gpa.deinit
    // Isso é LIFO (Last In, First Out) — ordem inversa de declaração
}
```

## Regra de Ouro

**Imediatamente após adquirir um recurso, escreva o defer para liberá-lo.**

```zig
// PADRÃO CORRETO:
const recurso = try adquirir();
defer liberar(recurso);
// ... usar recurso ...
```

Nunca escreva código entre a aquisição e o defer:

```zig
// PADRÃO PERIGOSO:
const recurso = try adquirir();
try fazerAlgo(); // Se falhar, recurso vaza!
defer liberar(recurso); // Tarde demais
```

## Lista de Padrões defer Comuns

| Aquisição | defer Correspondente |
|-----------|---------------------|
| `allocator.alloc(...)` | `defer allocator.free(...)` |
| `allocator.create(T)` | `defer allocator.destroy(ptr)` |
| `file.open(...)` | `defer file.close()` |
| `ArrayList.init(...)` | `defer lista.deinit()` |
| `HashMap.init(...)` | `defer mapa.deinit()` |
| `mutex.lock()` | `defer mutex.unlock()` |
| `ArenaAllocator.init(...)` | `defer arena.deinit()` |
| `GPA{}` | `defer _ = gpa.deinit()` |

## defer vs errdefer

```zig
// defer: executa SEMPRE ao sair do escopo
defer allocator.free(buf);

// errdefer: executa APENAS se a função retornar erro
errdefer allocator.free(buf);
```

Use `errdefer` quando a função retorna o recurso ao chamador em caso de sucesso:

```zig
fn criar(allocator: std.mem.Allocator) ![]u8 {
    const buf = try allocator.alloc(u8, 100);
    errdefer allocator.free(buf); // SÓ se houver erro
    try preencher(buf);
    return buf; // Sucesso: chamador recebe e é responsável
}
```

## Erros Relacionados

- [Memory leak](/erros/erro-memory-leak/) — Vazamento de memória
- [Allocator leak detected](/erros/erro-allocator-leak-detected/) — Leak detectado pelo GPA
- [Double free](/erros/erro-double-free/) — Liberar recurso duas vezes
- [Use after free](/erros/erro-use-after-free/) — Usar recurso após liberar

## Links Úteis

- [Documentação oficial do Zig — defer](https://ziglang.org/documentation/master/#defer)
- [Documentação oficial do Zig — errdefer](https://ziglang.org/documentation/master/#errdefer)
- [Receitas de gerenciamento de recursos](/receitas/)
- [Tutorial sobre ciclo de vida de recursos](/tutoriais/)
