# Ownership Rules

### Ownership Rules

Allocation creates a responsibility.

The program that owns allocated memory must release it. Zig does not guess who owns memory. Ownership must be visible from the code.

A common rule is simple:

The function that allocates memory frees it in the same scope.

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

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

    const bytes = try allocator.alloc(u8, 128);
    defer allocator.free(bytes);

    @memset(bytes, 0);

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

The allocation and free are close together:

```zig
const bytes = try allocator.alloc(u8, 128);
defer allocator.free(bytes);
```

This is the easiest ownership pattern to read.

Sometimes a function allocates memory and returns it. Then ownership moves to the caller.

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

fn makeBuffer(allocator: std.mem.Allocator, len: usize) ![]u8 {
    const bytes = try allocator.alloc(u8, len);
    @memset(bytes, 0);
    return bytes;
}

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

    const buffer = try makeBuffer(allocator, 256);
    defer allocator.free(buffer);

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

`makeBuffer` allocates the memory. `main` frees it.

The function signature gives the clue:

```zig
fn makeBuffer(allocator: std.mem.Allocator, len: usize) ![]u8
```

A returned slice may point to allocated memory. The caller must know whether it owns that memory.

This should be stated by convention, by name, and by documentation.

Do not hide ownership transfer.

For example, this function name is clear:

```zig
fn allocMessage(allocator: std.mem.Allocator) ![]u8
```

The word `alloc` tells the caller that memory is probably returned and must be freed.

This name is less clear:

```zig
fn message(allocator: std.mem.Allocator) ![]u8
```

The type is the same, but the ownership rule is harder to see.

Borrowing is different.

A borrowed slice points to memory owned by someone else. The borrower may read it, or sometimes modify it, but must not free it.

```zig
fn printLine(line: []const u8) void {
    std.debug.print("{s}\n", .{line});
}
```

This function does not allocate. It does not free. It only uses the slice while it runs.

The caller keeps ownership.

A slice does not say whether it owns memory. Both of these have the same type:

```zig
[]u8
```

One may be owned heap memory. Another may be a slice of a stack array. Another may point into a larger buffer.

Ownership is a program rule, not a separate slice type.

That is why Zig code should keep ownership simple.

A common mistake is returning a slice to local memory:

```zig
fn bad() []u8 {
    var buffer = [_]u8{ 'z', 'i', 'g' };
    return buffer[0..]; // wrong
}
```

`buffer` lives only while `bad` runs. After the function returns, the slice points to invalid memory.

Allocate when the result must outlive the function:

```zig
fn good(allocator: std.mem.Allocator) ![]u8 {
    const buffer = try allocator.alloc(u8, 3);
    buffer[0] = 'z';
    buffer[1] = 'i';
    buffer[2] = 'g';
    return buffer;
}
```

Then the caller frees it:

```zig
const s = try good(allocator);
defer allocator.free(s);
```

Another common mistake is freeing memory too early:

```zig
const bytes = try allocator.alloc(u8, 10);
allocator.free(bytes);

bytes[0] = 1; // wrong
```

After `free`, the slice must not be used.

Double free is also wrong:

```zig
const bytes = try allocator.alloc(u8, 10);

allocator.free(bytes);
allocator.free(bytes); // wrong
```

The program must release allocated memory exactly once.

Containers follow the same rule.

```zig
var list = std.ArrayList(u8).init(allocator);
defer list.deinit();

try list.appendSlice("zig");
```

The list owns its internal buffer. `deinit` releases it.

But `list.items` is only a view into the list's memory:

```zig
const items = list.items;
```

Do not free `items` directly. The list owns it.

The owner releases memory. Borrowers do not.

This rule applies to structs too.

```zig
const Buffer = struct {
    allocator: std.mem.Allocator,
    data: []u8,

    fn init(allocator: std.mem.Allocator, len: usize) !Buffer {
        const data = try allocator.alloc(u8, len);
        return Buffer{
            .allocator = allocator,
            .data = data,
        };
    }

    fn deinit(self: *Buffer) void {
        self.allocator.free(self.data);
        self.data = &[_]u8{};
    }
};
```

The struct stores the allocator because it owns `data`.

A caller uses it like this:

```zig
var b = try Buffer.init(allocator, 1024);
defer b.deinit();
```

This is a common Zig pattern:

```zig
init
deinit
```

`init` acquires resources. `deinit` releases them.

Ownership rules should be boring. The simpler they are, the fewer memory bugs the program has.

Exercises:

Exercise 12-21. Write a function named `allocZeros` that returns an allocated slice filled with zero bytes. Free it in the caller.

Exercise 12-22. Write a function that borrows a `[]const u8` and prints it without allocating.

Exercise 12-23. Explain why returning a slice to a local array is invalid.

Exercise 12-24. Write a small struct that owns an allocated buffer and releases it in `deinit`.

