释放 Zig 中 ArrayList 中项的内存的惯用方式([] const u8):

huangapple go评论50阅读模式
英文:

Idiomatic way to free item memory in a zig ArrayList([] const u8)

问题

我有一个ArrayList([]const u8)。我将一个指针传递给将其附加到函数的函数。它们将std.fmt.allocPrint()的调用结果附加到其中。为了释放所有内容,顶层函数在释放所有项目之后取消初始化ArrayList:

var typeLines = std.ArrayList([]const u8).init(allocator);
defer typeLines.deinit();
defer for (typeLines.items) |line| {
    allocator.free(line);
};

这个方法是有效的。但现在我有一些情况,调用的函数应该附加常量字符串。所以我不能简单地循环遍历所有项目并释放它们。

我考虑过检查每个项目的类型以确定是否需要释放它,或者可能保持一个单独的ArrayList,其中只包含需要释放的项目。什么是识别哪些项目需要释放的惯用方法?

英文:

I have an ArrayList([]const u8). I pass a pointer to it into functions that append to it. They append the results of calls to std.fmt.allocPrint(). To free everything up, the top-level function deinits the ArrayList after it frees all the items:

var typeLines = std.ArrayList([]const u8).init(allocator);
defer typeLines.deinit();
defer for (typeLines.items) |line| {
    allocator.free(line);
};

This works. But I have some cases now where the called functions should append constant strings. So I can't simply loop through the items and free them all.

I've thought about checking each item's type to see if I need to free it, or maybe keeping a separate ArrayList of just the items that need to be freed. What's the idiomatic way to identify which items need to be freed?

答案1

得分: 1

I ended up putting the []const u8 slice in a struct with a bool flag:

const Line = struct {
    text: []const u8,
    freeIt: bool,
};

I used the Line struct in the ArrayList:

var typeLines = std.ArrayList(Line).init(allocator);
defer typeLines.deinit();
defer for (typeLines.items) |line| {
    if (line.freeIt) {
        allocator.free(line.text);
    }
};

This lets the called functions control whether or not the caller frees their additions to the ArrayList:

var s = try std.fmt.allocPrint(allocator, "\npub const {s} = struct {\n", .{typeName});
try typeLines.append(Line{ .text = s, .freeIt = true });

try typeLines.append(Line{ .text = "\n};\n", .freeIt = false });
英文:

I ended up putting the []const u8 slice in a struct with a bool flag:

const Line = struct {
    text: []const u8,
    freeIt: bool,
};

I used the Line struct in the ArrayList:

var typeLines = std.ArrayList(Line).init(allocator);
defer typeLines.deinit();
defer for (typeLines.items) |line| {
    if (line.freeIt) {
        allocator.free(line.text);
    }
};

This lets the called functions control whether or not the caller frees their additions to the ArrayList:

var s = try std.fmt.allocPrint(allocator, "\npub const {s} = struct {{\n", .{typeName});
try typeLines.append(Line{ .text = s, .freeIt = true });

try typeLines.append(Line{ .text = "\n};\n", .freeIt = false });

答案2

得分: 1

我认为 ArenaAllocator 在这里是最佳解决方案。

它主要将所有分配存储在较大的缓冲区中,并可以一次性释放所有这些分配。因此,您无需逐个释放元素,也无需检查是否已分配它们。

const arena = std.heap.ArenaAllocator.init(allocator);
defer arena.deinit();

var typeLines = std.ArrayList(Line).init(allocator);
defer typeLines.deinit();

...
var s = try std.fmt.allocPrint(arena.allocator(), "\npub const {s} = struct {{\n", .{typeName});
try typeLines.append(s);

try typeLines.append("\n};\n");
英文:

I think an ArenaAllocator would be the best solution here.

It essentially stores all allocations in bigger buffers and can free these all at once. So you don't need to free elements individually, and you don't need to check if you allocated them.

const arena = std.heap.ArenaAllocator.init(allocator);
defer arena.deinit();

var typeLines = std.ArrayList(Line).init(allocator);
defer typeLines.deinit();

...
var s = try std.fmt.allocPrint(arena.allocator(), "\npub const {s} = struct {{\n", .{typeName});
try typeLines.append(s);

try typeLines.append("\n};\n");

huangapple
  • 本文由 发表于 2023年6月8日 23:21:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/76433397.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定