defer and errdefer
Deferred statements run in reverse order at block exit (not function exit, unlike Go).
errdefer |err| log(err); captures the error.
Pair every resource acquisition with an immediate defer/errdefer. This is Zig's alternative to RAII.
fn processFile(allocator: std.mem.Allocator, path: []const u8) !void {
const file = try std.fs.cwd().openFile(path, .{});
defer file.close(); // runs at scope exit (always)
const buf = try allocator.alloc(u8, 4096);
defer allocator.free(buf);
// ... use file and buf
}
fn createUser(allocator: std.mem.Allocator, name: []const u8) !*User {
const user = try allocator.create(User);
errdefer allocator.destroy(user); // runs ONLY if the function returns an error
user.name = try allocator.dupe(u8, name);
errdefer allocator.free(user.name);
try registerUser(user); // if this fails, both errdefers run
return user; // success: errdefers are skipped
}