# Lifetimes

### Lifetimes

A pointer is useful only while the value it points to still exists.

This is the lifetime of the value: the part of the program during which its storage is valid.

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

pub fn main() void {
    var x: i32 = 10;
    const p = &x;

    std.debug.print("{d}\n", .{p.*});
}
```

Here `x` exists until the end of `main`. The pointer `p` is valid during that time.

A local variable belongs to the block where it is declared.

```zig
{
    var x: i32 = 10;
    const p = &x;

    std.debug.print("{d}\n", .{p.*});
}

// x is gone here
```

After the block ends, `x` no longer exists. A pointer to `x` must not be used outside that block.

This is wrong:

```zig
fn bad() *i32 {
    var x: i32 = 10;
    return &x;
}
```

The function returns the address of a local variable. But `x` belongs to the call to `bad`. When `bad` returns, `x` is gone. The returned pointer would point to storage that no longer holds a valid `i32`.

A pointer may outlive the name used to create it only if the storage itself still exists.

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

var global_count: i32 = 0;

fn getCount() *i32 {
    return &global_count;
}

pub fn main() void {
    const p = getCount();
    p.* += 1;

    std.debug.print("{d}\n", .{global_count});
}
```

This is valid. `global_count` has static storage. It exists for the whole program.

Heap allocation is another way to create storage with a longer lifetime.

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

pub fn main() !void {
    const allocator = std.heap.page_allocator;

    const p = try allocator.create(i32);
    defer allocator.destroy(p);

    p.* = 42;

    std.debug.print("{d}\n", .{p.*});
}
```

The value pointed to by `p` exists until `allocator.destroy(p)` is called. The pointer must not be used after that.

```zig
allocator.destroy(p);

// p.* is invalid here
```

The pointer value still exists as a bit pattern, but it no longer refers to live storage.

Slices have lifetimes too. A slice refers to storage owned by something else.

```zig
fn firstThree() []i32 {
    var items = [_]i32{ 1, 2, 3 };
    return items[0..];
}
```

This has the same problem as returning `&x`. The slice points into a local array. When the function returns, the array is gone.

A safe function can ask the caller to provide the storage.

```zig
fn fill(items: []i32) void {
    for (items) |*item| {
        item.* = 0;
    }
}
```

The caller owns the array or slice. The function only uses it during the call.

```zig
pub fn main() void {
    var items = [_]i32{ 1, 2, 3 };
    fill(items[0..]);
}
```

This is the usual Zig style. The owner of the storage is clear.

A function may also allocate and return storage, but then ownership must be explicit.

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

fn makeNumbers(allocator: std.mem.Allocator) ![]i32 {
    const items = try allocator.alloc(i32, 3);

    items[0] = 1;
    items[1] = 2;
    items[2] = 3;

    return items;
}

pub fn main() !void {
    const allocator = std.heap.page_allocator;

    const numbers = try makeNumbers(allocator);
    defer allocator.free(numbers);

    std.debug.print("{d}\n", .{numbers[0]});
}
```

The function `makeNumbers` allocates a slice and returns it. The caller must free it. The lifetime of the slice ends when `allocator.free(numbers)` is called.

This convention is important. Zig does not use a garbage collector. The program must have a clear owner for allocated memory.

The same rule applies to structs that contain slices or pointers.

```zig
const Buffer = struct {
    data: []u8,
};
```

A `Buffer` does not own memory just because it has a slice field. The slice points somewhere. The program must still know who owns that memory and when it is freed.

```zig
const Buffer = struct {
    data: []u8,

    fn clear(self: *Buffer) void {
        for (self.data) |*b| {
            b.* = 0;
        }
    }
};
```

This method uses the slice. It does not allocate or free it.

A common bug is storing a pointer to temporary storage.

```zig
const Holder = struct {
    value: *i32,
};

fn makeHolder() Holder {
    var x: i32 = 10;
    return Holder{ .value = &x };
}
```

The returned `Holder` contains a bad pointer. The struct survived, but the value it points to did not.

The fix is to store the value itself, or allocate storage whose lifetime is long enough.

```zig
const Holder = struct {
    value: i32,
};

fn makeHolder() Holder {
    return Holder{ .value = 10 };
}
```

This version has no pointer and no lifetime problem.

Pointers are for sharing access to storage, not for avoiding ordinary values. If a value can be copied plainly, copy it. Use a pointer when identity, mutation, or large size matters.

`defer` is often used to make lifetimes visible.

```zig
const p = try allocator.create(i32);
defer allocator.destroy(p);
```

The allocation and its cleanup appear together. The pointer is valid between those two points.

For slices:

```zig
const buf = try allocator.alloc(u8, 1024);
defer allocator.free(buf);
```

The slice is valid until the deferred `free` runs.

A pointer may be valid, invalid, or optional. These are different ideas.

A valid pointer points to live storage.

```zig
const p: *i32 = &x;
```

An optional pointer may be absent.

```zig
const maybe: ?*i32 = null;
```

An invalid pointer is a bug. Zig does not use null to represent every invalid pointer. A non-optional pointer should point to real storage of the right type, alignment, and lifetime.

The practical rules are these:

```zig
// Do not return pointers to local variables.
// Do not return slices into local arrays.
// Do not use pointers after freeing their storage.
// Keep allocation and cleanup close together.
// Prefer values when no shared storage is needed.
```

Exercise 5-25. Write a function that fills a caller-provided slice with zeroes.

Exercise 5-26. Try to return a slice into a local array. Read the compiler error or observe why the code is invalid.

Exercise 5-27. Allocate one `i32`, assign it a value, print it, and free it.

Exercise 5-28. Define a struct with a slice field. Write a function that uses the slice but does not free it.

