提问人:William Ryman 提问时间:10/24/2023 更新时间:11/1/2023 访问量:192
如何在 Zig 的 comptime 中指定分配器?
How Can I Specify an Allocator at Comptime in Zig?
问:
在 Zig 中,我想指定一个分配器,以消除将分配器传递给每个需要它的函数的额外开销。在下面的 MWE 中,我有一个类型生成器,它接受并返回一个类型,其中该分配器作为“静态”成员。实例化类型,调用 ,然后使用先前指定的分配器初始化对象。comptime
comptime
ArenaAllocator
MyType
MyType
const std = @import("std");
fn MyTypeGen(comptime arena: *std.heap.ArenaAllocator) type {
return struct {
var allocator = arena.allocator();
data: []const u8,
pub fn init(data: []const u8) !@This() {
const temp = try allocator.alloc(u8, data.len);
@memcpy(temp, data);
return .{ .data = temp };
}
};
}
pub fn main() !void {
comptime var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const MyType = MyTypeGen(&arena);
const val = try MyType.init(&[_]u8{ 1, 2, 3 });
std.debug.print("{}\n", .{val});
}
问题是上面的代码失败并出现隔离错误:
Segmentation fault at address 0x7ff63e46b628
C:\Program Files\zig\lib\std\heap\arena_allocator.zig:171:39: 0x7ff63e3f2788 in createNode (Calculator.exe.obj)
self.state.buffer_list.prepend(buf_node);
^
C:\Program Files\zig\lib\std\heap\arena_allocator.zig:184:29: 0x7ff63e3f216a in alloc (Calculator.exe.obj)
(self.createNode(0, n + ptr_align) orelse return null);
^
C:\Program Files\zig\lib\std\mem\Allocator.zig:225:53: 0x7ff63e4242dd in allocBytesWithAlignment__anon_6797 (Calculator.exe.obj)
const byte_ptr = self.rawAlloc(byte_count, log2a(alignment), return_address) orelse return Error.OutOfMemory;
^
C:\Program Files\zig\lib\std\mem\Allocator.zig:211:40: 0x7ff63e3f2e37 in allocWithSizeAndAlignment__anon_3321 (Calculator.exe.obj)
return self.allocBytesWithAlignment(alignment, byte_count, return_address);
^
C:\Program Files\zig\lib\std\mem\Allocator.zig:129:41: 0x7ff63e3f11f3 in alloc__anon_3262 (Calculator.exe.obj)
return self.allocAdvancedWithRetAddr(T, null, n, @returnAddress());
^
C:\...\src\main.zig:10:45: 0x7ff63e3f1044 in init (Calculator.exe.obj)
const temp = try allocator.alloc(u8, data.len);
^
C:\...\src\main.zig:24:32: 0x7ff63e3f1486 in main (Program.exe.obj)
const val = try MyType.init(&[_]u8{ 1, 2, 3 });
^
C:\Program Files\zig\lib\std\start.zig:348:65: 0x7ff63e3f175c in WinStartup (Program.exe.obj)
std.os.windows.kernel32.ExitProcess(initEventLoopAndCallMain());
^
???:?:?: 0x7ffee8867343 in ??? (KERNEL32.DLL)
???:?:?: 0x7ffeea8426b0 in ??? (ntdll.dll)
run Program: error: the following command exited with error code 3:
C:\...\zig-out\bin\Program.exe
Build Summary: 3/5 steps succeeded; 1 failed (disable with --summary none)
run transitive failure
+- run Program failure
error: the following build command failed with exit code 1:
C:\...\zig-cache\o\03618dc1d07de7a2b7ce2381e69121e1\build.exe C:\Program Files\zig\zig.exe C:\... C:\...\zig-cache C:\...\AppData\Local\zig run
问题似乎是 Windows 指定了堆分配器,该分配器在运行时支持 ,这意味着错误地初始化了。Zig 一定不能在编译时抱怨表面上的运行时依赖性,因此会出现段错误。ArenaAllocator
comptime var arena
如何在 comptime
成功初始化竞技场分配器?
也欢迎使用不需要以上述方式初始化分配器的指定分配器的替代方法。comptime
答:
1赞
sigod
11/1/2023
#1
将分配器包装在其自己的全局类型中似乎有效。
const std = @import("std");
const GlobalArena = struct {
var global_arena: std.heap.ArenaAllocator = undefined;
fn init(arena: std.heap.ArenaAllocator) void {
global_arena = arena;
}
fn deinit() void {
global_arena.deinit();
global_arena = undefined;
}
fn allocator() std.mem.Allocator {
return global_arena.allocator();
}
};
fn MyTypeGen(comptime GlobalAllocator: type) type {
return struct {
var allocator = GlobalAllocator.allocator();
data: []const u8,
pub fn init(data: []const u8) !@This() {
const temp = try allocator.alloc(u8, data.len);
@memcpy(temp, data);
return .{ .data = temp };
}
};
}
pub fn main() !void {
GlobalArena.init(std.heap.ArenaAllocator.init(std.heap.page_allocator));
defer GlobalArena.deinit();
const MyType = MyTypeGen(GlobalArena);
const val = try MyType.init(&[_]u8{ 1, 2, 3 });
std.debug.print("{}\n", .{val});
}
$ zig version
0.12.0-dev.587+eb072fa52
$ zig build run
main.MyTypeGen(main.GlobalArena){ .data = { 1, 2, 3 } }
评论
Allocator
comptime