Beginner allocator questions

Hi all.

I’m trying some simple examples to try get a better grasp on allocators.
In my code below, I’m trying to read a file line by line and return a slice of strings.
2 things are not clear to me:
1: my ArrayList always reports that it’s leaking memory
2: Is there a better way to free the items of the ArrayList with a defer instead of a for loop

fn readInput(in_file: std.fs.File, allocator: Allocator) ![][]u8 {
    const reader = in_file.reader();
    var list = std.ArrayList([]u8).init(allocator);
    defer list.deinit();
    const line = try reader.readUntilDelimiterOrEofAlloc(allocator, '\n', 256);
    try list.append(line.?);
    return try list.toOwnedSlice();
}

pub fn main() !void {
    const in_file = try std.fs.cwd().openFile("input.txt", .{});
    defer in_file.close();
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const strings = try readInput(in_file, allocator);
    std.debug.print("Length of strings is {d}\n", .{strings.len});
    for (strings) |s| {
        allocator.free(s);
    }
}

(Yes, I’m only reading a single line from the file at the moment, will extend as soon as I can understand the problems I’m having)

Does anyone have some tips for me on what I’m doing wrong?
Thanks in advance.

The leak is because you’re not freeing the strings slice itself. defer and errdefer can use blocks, so I’d do:

// in readInput
    var list = std.ArrayList([]u8).init(allocator);
    errdefer {
        for (list.items) |s| {
            allocator.free(s);
        }
        list.deinit();
    }

// in main
    const strings = try readInput(in_file, allocator);
    defer {
        for (strings) |s| {
            allocator.free(s);
        }
        allocator.free(strings);
    }
3 Likes